C++11 compiler generated functions - c++

Say a class
class Piece {} ;
If I'm correct that should be equivalent to :
class Piece {
//C++ 03
Piece (); //default constructor
Piece( const Piece&); //copy constructor
Piece& operator=(const Piece&); //copy assignment operator
~Piece(); //destructor
//Since C++ 11
Piece(Piece&&); //move constructor
Piece& operator=(Piece&&); //move assignment operator
};
So what can I say about these ?
a)
class Pawn{
~Pawn() {}// Only destructor
};
b)
class Bishop{
Bishop(Bishop&& ) {}// Only move constructor
};
c)
class Knight{
Knight(Knight&&, int =0) {} // move constructor, when no second arg present
};
d)
class Rook {
Rook(const Rook& ) {}// Only copy constructor
};
e)
class King{
King& operator=(const King&) = delete;
};
My per my understanding compiler will generate for :
a) Default Constructor, Copy Constructor, Copy Assignment operator , ( move constructor/assignment operator ? )
b) Destructor
c) Destructor
d) Copy Assignment operator and Destructor ( move constructor/assignment operator ? )
e) Default Constructor, Copy Constructor, Destructor, ( move constructor/assignment operator ? )
Am I correct or missing something here ?
Basically is C++11 has any new rules for generating functions, when not provided by user ?

I'll leave out some irrelevant points here, e.g. about unions, base classes, brace-or-equal-initializers etc. If your classes have any members, base classes, ... then the answer will differ. For example, if you have a const member, an implicitly declared assignment operator would be defined as deleted.
default constructor
[class.ctor]/5
A default constructor for a class X is a constructor of class X that can be called without an argument. If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted. An implicitly-declared default constructor is an inline public member of its class. A defaulted default constructor for class X is defined as deleted if [... lots of points irrelevant here].
So in cases a) and e) [without any user-declared ctor], a default ctor is declared as defaulted.
default destructor
[class.dtor]
4 If a class has no user-declared destructor, a destructor is implicitly declared as defaulted. An implicitly-declared destructor is an inline public member of its class.
5 A defaulted destructor for a class X is defined as deleted if [... lots of points irrelevant here]
So in all cases but a) [with a user-declared dtor], a default dtor is implicitly declared and implicitly defined if odr-used.
As per [class.copy]/2+3, a copy-ctor and move-ctor may have additional parameters, if those have default arguments.
copy-constructor
A copy-ctor is declared implicitly if there's no user-defined copy-ctor (a ctor template is never a copy-ctor). [class.copy]/7
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted. The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
That is, in all cases but d) [with a user-declared copy-ctor], a copy-ctor is declared implicitly. In cases b) and c) [with a user-provided move ctor], the copy-ctor is defined as deleted. For a) [user-declared dtor] and e) [user-declared copy-assignment op], it may be defined as defaulted, but that's deprecated.
move-constructor
The move-ctor won't even be declared in these cases [class.copy]/9
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
There are again quite some cases where it would be defined as deleted, but they don't apply here.
Therefore, the move-ctor is not declared in any of the cases.
copy-assignment operator
In [class.copy]/18:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted. The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
It is defined as deleted in some cases, see [class.copy]/23, but they don't apply here.
The copy-assignment op is declared in all cases but e) [user-declared copy-assignment op]. It is defined as deleted in b) and c) [both: user-declared move ctor]; and it may be defined as defaulted in a) [user-declared dtor] and d) [user-declared copy-ctor]. Note the parallel to the copy-ctor.
move-assignment operator
Similar to the move-ctor, the move-assignment op is not even declared if either [class.copy]/20:
X does not have a user-declared copy constructor,
X does not have a user-declared move constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared destructor, and
the move assignment operator would not be implicitly defined as deleted.
It is defined as deleted in some cases, see [class.copy]/23 (same paragraph as for the copy-ctor), but they don't apply here.
A move-assignment-op is declared implicitly and defined as defaulted in none of the cases.

So looking at some post and online tutorials, I concluded this :
Generated functions :-
C++ 03:
1) Default Constructor (generated only if no constructor is declared by user)
2) Copy Constructor (generated only if No. 5,6 declared by user)
3) Copy Assignment operator (generated only if 5,6 not declared by user)
4) Destructor
Since C++ 11:
5) Move Constructor (generated only if 2,3,4,6 not declared by user)
6) Move Assignment Operator (generated only if 2,3,4,5 not declared by user)
So, for
a)
class Pawn{ //1, 2, 3
~Pawn() {}// Only destructor
};
b)
class Bishop{ //4
Bishop(Bishop&& ) {}
};
c)
class Knight{ //4
Knight(Knight&&, int =0) {}
};
d)
class Rook { //3, 4
Rook(const Rook& ) {}
};
e)
class King{ //1, 2, 4
King& operator=(const King&) = delete;
};
Edit : As per DyP comment :-
In C++11,
For case a), 2 and 3 are deprecated.
For case d), 3 is deprecated.
For case e), 2 is deprecated.

Related

C++ primer 5 ed. Virtual destructor and move semantics

In C++ primer 5 ed. it is said:
"The fact that a base class needs a virtual destructor has an important indirect impact on the definition of base and derived classes: If a class defines a destructor—even if it uses = default to use the synthesized version—the compiler will not synthesize a move operator for that class (§13.6.2, p. 537)."
So for more understanding I've tried this:
class A
{
public:
A(){cout << "A::A()\n";}
virtual ~A(){cout << "A::~A()\n";}
A& operator = (const A&) {cout << "A::=\n"; return *this;};
A& operator = (A&&) = default;
};
int main()
{
A a;
A a2;
a2 = std::move(a); // why copy-assignment operator is not called here. Normally a will be "moved" through copy-ctor (moving through working copy-ctor)
std::cout << std::endl;
}
So according to the text above in the book class A has a virtual destructor thus the compiler won't synthesize a move-ctor/assignment operations But in main I've tried to move an object of type class A so normally move here uses copy-assignment instead of move-assignment but copy-assignment is not called here?!
So when a vairtual dtor causes a default operation be not synthesized? Thank you!
Your textbook is right, the compiler won't automatically synthesize a move operator. In the code sample you force the compiler to generate one by setting it to default, this can only fail if the move operator is implicitly deleted. Which is something else than it being implicitly declared.
Criteria for implicit deletion:
A has a non-static data member that is const
A has a non-static data member of a reference type
A has a non-static data member that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator)
A has direct or virtual base class that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator)
A has a non-static data member or a direct or virtual base without a move assignment operator that is not trivially copyable
A has a direct or indirect virtual base class
Criteria for implicit declaration:
there are no user-declared copy constructors;
there are no user-declared move constructors;
there are no user-declared copy assignment operators;
there are no user-declared destructors;
the implicitly-declared move assignment operator would not be defined as deleted
source

When does each type of special function get implicitly deleted? [duplicate]

Say a class
class Piece {} ;
If I'm correct that should be equivalent to :
class Piece {
//C++ 03
Piece (); //default constructor
Piece( const Piece&); //copy constructor
Piece& operator=(const Piece&); //copy assignment operator
~Piece(); //destructor
//Since C++ 11
Piece(Piece&&); //move constructor
Piece& operator=(Piece&&); //move assignment operator
};
So what can I say about these ?
a)
class Pawn{
~Pawn() {}// Only destructor
};
b)
class Bishop{
Bishop(Bishop&& ) {}// Only move constructor
};
c)
class Knight{
Knight(Knight&&, int =0) {} // move constructor, when no second arg present
};
d)
class Rook {
Rook(const Rook& ) {}// Only copy constructor
};
e)
class King{
King& operator=(const King&) = delete;
};
My per my understanding compiler will generate for :
a) Default Constructor, Copy Constructor, Copy Assignment operator , ( move constructor/assignment operator ? )
b) Destructor
c) Destructor
d) Copy Assignment operator and Destructor ( move constructor/assignment operator ? )
e) Default Constructor, Copy Constructor, Destructor, ( move constructor/assignment operator ? )
Am I correct or missing something here ?
Basically is C++11 has any new rules for generating functions, when not provided by user ?
I'll leave out some irrelevant points here, e.g. about unions, base classes, brace-or-equal-initializers etc. If your classes have any members, base classes, ... then the answer will differ. For example, if you have a const member, an implicitly declared assignment operator would be defined as deleted.
default constructor
[class.ctor]/5
A default constructor for a class X is a constructor of class X that can be called without an argument. If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted. An implicitly-declared default constructor is an inline public member of its class. A defaulted default constructor for class X is defined as deleted if [... lots of points irrelevant here].
So in cases a) and e) [without any user-declared ctor], a default ctor is declared as defaulted.
default destructor
[class.dtor]
4 If a class has no user-declared destructor, a destructor is implicitly declared as defaulted. An implicitly-declared destructor is an inline public member of its class.
5 A defaulted destructor for a class X is defined as deleted if [... lots of points irrelevant here]
So in all cases but a) [with a user-declared dtor], a default dtor is implicitly declared and implicitly defined if odr-used.
As per [class.copy]/2+3, a copy-ctor and move-ctor may have additional parameters, if those have default arguments.
copy-constructor
A copy-ctor is declared implicitly if there's no user-defined copy-ctor (a ctor template is never a copy-ctor). [class.copy]/7
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted. The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
That is, in all cases but d) [with a user-declared copy-ctor], a copy-ctor is declared implicitly. In cases b) and c) [with a user-provided move ctor], the copy-ctor is defined as deleted. For a) [user-declared dtor] and e) [user-declared copy-assignment op], it may be defined as defaulted, but that's deprecated.
move-constructor
The move-ctor won't even be declared in these cases [class.copy]/9
X does not have a user-declared copy constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared move assignment operator,
X does not have a user-declared destructor, and
the move constructor would not be implicitly defined as deleted.
There are again quite some cases where it would be defined as deleted, but they don't apply here.
Therefore, the move-ctor is not declared in any of the cases.
copy-assignment operator
In [class.copy]/18:
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted. The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
It is defined as deleted in some cases, see [class.copy]/23, but they don't apply here.
The copy-assignment op is declared in all cases but e) [user-declared copy-assignment op]. It is defined as deleted in b) and c) [both: user-declared move ctor]; and it may be defined as defaulted in a) [user-declared dtor] and d) [user-declared copy-ctor]. Note the parallel to the copy-ctor.
move-assignment operator
Similar to the move-ctor, the move-assignment op is not even declared if either [class.copy]/20:
X does not have a user-declared copy constructor,
X does not have a user-declared move constructor,
X does not have a user-declared copy assignment operator,
X does not have a user-declared destructor, and
the move assignment operator would not be implicitly defined as deleted.
It is defined as deleted in some cases, see [class.copy]/23 (same paragraph as for the copy-ctor), but they don't apply here.
A move-assignment-op is declared implicitly and defined as defaulted in none of the cases.
So looking at some post and online tutorials, I concluded this :
Generated functions :-
C++ 03:
1) Default Constructor (generated only if no constructor is declared by user)
2) Copy Constructor (generated only if No. 5,6 declared by user)
3) Copy Assignment operator (generated only if 5,6 not declared by user)
4) Destructor
Since C++ 11:
5) Move Constructor (generated only if 2,3,4,6 not declared by user)
6) Move Assignment Operator (generated only if 2,3,4,5 not declared by user)
So, for
a)
class Pawn{ //1, 2, 3
~Pawn() {}// Only destructor
};
b)
class Bishop{ //4
Bishop(Bishop&& ) {}
};
c)
class Knight{ //4
Knight(Knight&&, int =0) {}
};
d)
class Rook { //3, 4
Rook(const Rook& ) {}
};
e)
class King{ //1, 2, 4
King& operator=(const King&) = delete;
};
Edit : As per DyP comment :-
In C++11,
For case a), 2 and 3 are deprecated.
For case d), 3 is deprecated.
For case e), 2 is deprecated.

What is causing the move constructor to be deleted

I have the following sample:
#include <vector>
class noncopyable {
protected:
noncopyable() {}
~noncopyable() {}
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
noncopyable(noncopyable&&) = default;
noncopyable& operator=(noncopyable&&) = default;
};
class C1 : private noncopyable {
public:
C1() { }
~C1() { }
};
int main() {
std::vector<C1> v;
v.emplace_back();
return 0;
}
I thought it should work since C1 should be movable since it's base class is and it has no data members. Instead, I got an an error (using clang++):
error: call to implicitly-deleted copy constructor of 'C1'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
.
.
.
note: in instantiation of function template specialization 'std::vector<C1, std::allocator<C1> >::emplace_back<>' requested here
v.emplace_back();
^
note: copy constructor of 'C1' is implicitly deleted because base class 'noncopyable' has a deleted copy constructor
class C1 : private noncopyable {
^
note: 'noncopyable' has been explicitly marked deleted here
noncopyable(const noncopyable&) = delete;
Doing a little research (http://en.cppreference.com/w/cpp/language/move_constructor) revealed that if there is a user-defined destructor then no implicit move-constructor will be defined. This seemes to be the problem here, since C1 has a destructor, the move-constructor does not get defined. Sure enough, if I either remove the destructor or add C1(C1&&) = default; to C1 then it works.
So far so good.
The problem was that the error message didn't mention ~C1() or the move-constructor. It said it was trying to call the copy constructor, which was deleted in the base class. So I tried changing the deleteed functions in noncopyable to be defaulted instead, and (surprise!), that also solved the error.
So my question is, what does this last thing have to do with the error or it's correction? If there is a destructor, what is the difference if the base class has the copy-constructor or not?
You don't need vector, a simpler example would be just:
C1 a;
C1 b(std::move(a)); // error: C1's copy constructor is deleted
From [class.copy]:
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if
(9.1) — X does not have a user-declared copy constructor,
(9.2) — X does not have a user-declared copy assignment operator,
(9.3) — X does not have a user-declared move assignment operator, and
(9.4) — X does not have a user-declared destructor.
C1 has a user-declared destructor, therefore it does not have a move constructor. C1 does however have an implicitly declared copy constructor
If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy
constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
The full set of constructors on C1, explicit and implicit, looks like:
C1();
C1(C1 const& ) = default; // but also delete
~C1();
So trying to construct a C1 from an rvalue of type C1 will match that implicitly declared copy constructor as the best match (nothing else is viable), but that constructor is deleted because noncopyable's copy constructor is deleted, so the entire expression is ill-formed.
That's why the error message mentions the constructor. That move-construction is ill-formed because the best match for that move-construction is the copy constructor is ill-formed. It can't mention the move constructor because there is no move constructor, and the destructor isn't relevant to the expression at hand. When you changed the base class to be copyable, now C1 also becomes copyable - so no error. There's still no move constructor, it's just that now there's a viable candidate for move construction.

Is a private move constructor to prevent move?

A common pattern in C++ is to make the copy constructor private:
class A
{
public:
// ...
private:
A(const A&);
};
But will the following code then compile (in C++11/14):
A f();
auto a = f();
The standard contains information about automatically generating move constructors. I neither have access to the standard nor a compiler which actually generates move constructors. My question is: do I have to write
class A
{
public:
// ...
private:
A(const A&);
A(const A&&);
};
to prevent moving as well (and operators= analogously)?
But will the following code then compile (in C++11/14):
No, it will not. The presence of a user-declared copy constructor should inhibit the implicit generation of a move constructor. Per paragraph 12.8/9 of the C++11 Standard:
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared
as defaulted if and only if
— X does not have a user-declared copy constructor,
— X does not have a user-declared copy assignment operator,
— X does not have a user-declared move assignment operator,
— X does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.

Do derived classes indirectly inherit base's assignment operator?

I'm trying to understand this behaviour but it seems I don't. Please see this code:
#include <iostream>
using namespace std;
class Base
{
public:
void operator=(const Base& rf)
{
cout << "base operator=" << endl;
this->y = rf.y;
}
int y;
Base() : y(100) { }
};
class Derived : public Base
{
public:
int x;
Derived() : x(100) { }
};
int main()
{
Derived test;
Derived test2;
test2.x = 0;
test2.y = 0;
test.operator=(test2); // operator auto-generated for derived class but...
cout << test.x << endl << test.y << endl;
cin.ignore();
return 0;
}
PROGRAM OUTPUT:
> base operator=
> 0
> 0
Now where I'm confused is:
The rule says that a derived class never inherits the assigment operator, instead it creates its own operator= however in this example base's operator= gets invoked on the derived class.
Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.
Now if I understand it correctly, this means that any user defined base's operator always gets invoked on the derived class?
The generated ones automatically call the base-class assignment operator.
// generated version looks basically like this
Derived& operator=(Derived const& other){
Base::operator=(static_cast<Base const&>(other));
x = other.x;
return *this;
}
The cast is there to avoid an accidential call to a templated Base::operator= like this one:
template<class Other>
Base& operator=(Other const& other); // accepts everything
Or a strange one like this:
// forward-declare 'Derived' outside of 'Base'
Base& operator=(Derived const& other); // accepts derived class (for whatever reason)
Second I was able to explicitly invoke an assigment operator on a derived class, which isn't in turn explicitly defined in the derived class.
The compiler automatically declares an assignment operator if you do not and your class allows it (i.e., no reference members and some other arcane rules) and additionally defines it if you actually use it somewhere.
The compiler-generated assignment operator calls the assignment operator of each subobject. That includes base classes and non-static member variables.
The standard says (section 12.8 [class.copy]):
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor. The implicitly-declared copy assignment operator for a class X will have the form
X& X::operator=(const X&)
if
each direct base class B of X has a copy assignment operator whose parameter is of type const B&,
const volatile B& or B, and
for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.
Otherwise, the implicitly-declared copy assignment operator will have the form
X& X::operator=(X&)
and
The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Let x be either the parameter of the function
or, for the move operator, an xvalue referring to the parameter. Each subobject is assigned in the manner appropriate to its type:
if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);
if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
if the subobject is of scalar type, the built-in assignment operator is used.
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy assignment operator.
That's because the implicitly defined operator = calls the base classes operator =. See the FAQ lite:
I'm creating a derived class; should my assignment operator call my base class's assignment operator?
Yes (if you need to define an assignment operator in the first place).
If you define your own assignment operator, the compiler will not automatically call your base class's assignment operator for you. Unless your base class's assignment operator itself is broken, you should call it explicitly from your derived class's assignment operator (again, assuming you create one in the first place).
However if you do not create your own assignment operator, the one that the compiler creates for you will automatically call your base class's assignment operator.
4 things never get inherited
Constructor
Copy-constructor
Assignment operator
Destructor
Even you have not written the assignment operator your code will be Woking fine.
Whenever you use assignment operator compiler will make sure that assignment operator for each member object and base class get called.