What is causing the move constructor to be deleted - c++

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.

Related

Why deleting copy constructor for member variable doesnt prevent defaulting copy constructor

class A {
public:
A() = default;
A(const A&) = delete;
A(A&&) = delete;
};
class B {
public:
B() = default;
B(const B&) = default;
B(B&&) = default;
A a_;
};
int main() {
B b{};
static_cast<void>(b);
}
Why does this compile? the copy constructor should not have a default definition, since A has a deleted copy constructor.
What does a default copy constructor mean in such a case?
What am I missing here?
Declaring a special member as defaulted does not mean that there will be a usable definition. Rather, = default means "fill in the plausible meaning here", and that can also mean that the member ends up being defined as deleted, if that's the only plausible thing (e.g. if class members aren't copyable).
The precise rules are in [class.copy.ctor]:
[...] A defaulted copy/move constructor for a class X is defined as deleted (9.4.3) if X has:
a potentially constructed subobject type M (or array thereof) that cannot be copied/moved because overload resolution (11.3), as applied to find M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
[...]
That is, your B::B(const B&) ends up being defined as deleted. You will notice this as soon as you're trying to make a copy of b.
The default here translates to delete I think. Someone needs to lookup the standards document to confirm it. But if you added a line in your main() which was B foo = b;, you will start getting compiler errors I am sure. You won't be able to copy B in spite of the default keyword used for copy ctor.
EDIT: Here is the error I got when I tried copying B.
‘B::B(const B&)’ is implicitly deleted because the default definition
would be ill-formed

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.

Deleted destructor in the class appeared as a virtual/direct base class or as a type of non-static data member

There is a rule about cases when the copy/move constructor is implicitly deleted:
An implicitly-declared copy/move constructor is an inline public
member of its class. A defaulted copy/ move constructor for a class X
is defined as deleted (8.4.3) if X has:
[...]
— any direct or virtual base class or non-static data member of a type
with a destructor that is deleted or inaccessible from the defaulted
constructor, or
[...]
Because I can't find an example reflecting the rule, it's not clear to me. Consider the following code:
struct A
{
~A() = delete;
};
struct B : A
{
A a;
B(){ }; //error error: attempt to use a deleted function B(){ };
B(const B&&) = delete;
};
B *b = new B;
int main() { }
DEMO
Because of deleted move constructor doesn't take a part in overload resolution, I expected the error would be something like "Copy constructor is implicitly deleted". But instead I got the error about deleted B(), which I defined explicitly. Couldn't you provide an example reflecting that rule?
Based only on the excerpt you've provided, the following is an example:
struct inner
{
~inner() = delete;
};
struct outer
{
inner inst;
// Can't destroy "inst"; outer now has an implicitly
// deleted destructor and copy/move constructor.
};
Look at 5th point: it is clearly saying that you have deleted your base class dtor so you are having this problem.
link: http://en.cppreference.com/w/cpp/language/default_constructor
Deleted implicitly-declared default constructor
The implicitly-declared or defaulted default constructor for class T is undefined (until C++11)defined as deleted (since C++11) if any of the following is true:
T has a member of reference type without a brace-or-equal
initializer. (since C++11)
T has a const member without user-defined default constructor or a
brace-or-equal initializer (since C++11).
T has a member (without a brace-or-equal initializer) (since C++11),
which has a deleted default constructor, or its default constructor
is ambiguous or inaccessible from this constructor.
T has a direct or virtual base which has a deleted default
constructor, or it is ambiguous or inaccessible from this
constructor.
T has a direct or virtual base which has a deleted destructor, or a
destructor that is inaccessible from this constructor.
T is a union with at least one variant member with non-trivial
default constructor.
(since C++11)
T is a union and all of its variant members are const.

C++11 compiler generated functions

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.

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.