Looking at this question it mentions C++11 and later only:
The move constructor is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move constructor is valid (e.g. if it wouldn't need to assign constant members) (§12.8/10).
So if I have the following code:
class Y
{
public:
Y(const Y&) {}
};
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};
hasY hy, hy2 = std::move(hy); //this line fails as expected as Y has a user-defined copy constructor.
Now if I add the default constructor to Y:
Y() {}
The error goes away.
Where does it say that the default constructor causes the creation of the move constructor?
(using VS 2015 update 2)
class Y
{
public:
Y(const Y&) {}
};
This class has no default constructor, so
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem; // << requires default ctor
};
the error you were getting had nothing to do with move constructors:
prog.cpp: In function 'int main()':
prog.cpp:13:7: error: use of deleted function 'hasY::hasY()'
hasY hy;
^
prog.cpp:8:5: note: 'hasY::hasY()' is implicitly deleted because the default definition would be ill-formed:
hasY() = default;
http://ideone.com/u46GWS
It is nothing related to the move constructor It is about the default constructor. Try this:
class Y
{
public:
Y(const Y&) {}
};
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};
hasY hy; // This will cause an error because there is no default constructor
Now if you add the default constructor: Y(){}, the error will go away.
As #M.M commented, The copy constructor will be called in a such case.
You may try this code:
class Y{
public:
Y(){std::cout << "Default constructor\n";}
Y(const Y&) {std::cout << "Copy constructor\n";}
};
struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};
int main(){
hasY hy;
hasY h=std::move(hy);
}
It will print:
Default constructor
Copy constructor
If you want to make the class not moveable you should delete the move constructor by yourself Y(Y&&)=delete;
Where does it say that the default constructor causes the creation of the move constructor?
There is no relationship between the creation of the move constructor and the existence, or lack thereof, of the default constructor.
From the C++11 Standard:
12.8 Copying and moving class objects
...
9 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.
Related
class A {
public:
A() {}
A(const A& a) { cout << "A::A(A&)" << endl; }
};
class B {
public:
explicit B(A aa) {}
};
int main() {
A a;
B b(a);
return 0;
}
Why does it print "A::A(A&)"?
When was the copy constructor for "A" called? And if the code calls the copy constructor, why can I remove the copy constructor without creating a compilation error?
B(A aa) takes an A by value, so when you execute B b(a) the compiler calls the copy constructor A(const A& a) to generate the instance of A named aa in the explicit constructor for B.
The reason you can remove the copy constructor and have this still work is that the compiler will generate a copy constructor for you in cases where you have not also declared a move constructor.
Note: The compiler generated copy constructor is often not sufficient for complex classes, it performs a simple member wise copy, so for complex elements or dynamically allocated memory you should declare your own.
§ 15.8.1
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 (11.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a user-declared destructor or assignment operator.
Why the copy happens
Look at your class B c'tor:
class B {
public:
explicit B(A aa) {}
};
You receive A by value, triggering a copy during the call.
If you would have change it to (notice A & aa):
class B {
public:
explicit B(A & aa) {}
};
There wouldn't be any copy...
Default copy constructor
When you remove the c'tor, the compiler generates one for you when it can trivially do so:
First, you should understand that if you do not declare a copy
constructor, the compiler gives you one implicitly. The implicit
copy constructor does a member-wise copy of the source object.
The default c'tor is equivalent to:
MyClass::MyClass( const MyClass& other ) :
x( other.x ), c( other.c ), s( other.s ) {}
Exceptions use the statical type of an object to copy-initialize the thrown object. For instance:
struct foo
{
foo() = default;
foo(const foo&) = delete;
};
int main()
{
throw foo();
}
Clang++ --std=c++14 complains that the explicitly-deleted copy constructor can't be used. Why can't it be move-initialized instead?
It can't be move constructed because the type has no move constructor. A deleted copy constructor suppresses the implicit move constructor.
Modify the code to the following:
struct foo
{
foo() = default;
foo(const foo&) = delete;
foo(foo&&) = default;
};
int main()
{
throw foo();
}
Read this, the section "Implicitly-declared move constructor".
Because foo(foo&& ); is missing. By deleteing the copy constructor you've supressed move constructor as well.
The applicable phrasing from the standard (§[class.copy]/9) looks roughly like this (well, exactly like this, as of N4296):
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 ctor,
[...]
This applies because defining the copy ctor as deleted still means you've declared the copy ctor.
Take a look a the following code example which uses class uncopiable similar to boost::noncopyable:
#include <vector>
class uncopiable {
using self = uncopiable;
protected:
uncopiable() {}
~uncopiable() {}
uncopiable(const self&) = delete;
self& operator=(const self&) = delete;
};
struct A {
struct B : uncopiable {
using self = B;
B() {
}
B(B&&) = default;
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {}
Since I wanted to make inner class move only I explicitly specified its move constructor and assignment operator to be default ones but also since I've heard that it's a good practice to specify all of the "special member functions" in such case I inherited it from uncopiable. The problem is that compilation fails with every compiler and something similar to the following error message is displayed (this message is excerpt from the clang one):
/usr/include/c++/v1/memory:1645:31: error: call to implicitly-deleted copy constructor of 'A::B'
...
main.cpp:26:10: note: in instantiation of function template specialization 'std::__1::vector >::emplace_back<>' requested here
main.cpp:19:3: note: copy constructor is implicitly deleted because 'B' has a user-declared move constructor
It could be fixed by removing inheritance (copy operations would still not be created). But writing copy operations to be explicitly deleted inside class after that is also okay.
My questions are: why does it happen? Could it be considered a deficiency of disabling constructors/assignment operators through inheritance of helper classes?
The problem is that your uncopiable class is not moveable. Therefore the default move constructor / assignment operator of the derived class try to use the deleted copy versions.
static_assert(std::is_move_constructible<uncopiable>::value, ""); // fails
static_assert(std::is_move_assignable<uncopiable>::value, ""); // fails
The reason for this is § 12.8 ¶ 9:
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, and
X does not have a user-declared destructor.
Declaring a copy operator or assignment operator as deleted still counts as declaring it.
The solution is of course to declare the move operations for uncopiable.
uncopiable(uncopiable&&) noexcept = default;
uncopiable& operator=(uncopiable&&) noexcept = default;
Note that the move operations should usually be declared noexcept. Especially if you want to use the type in a std::vector like in your example.
This compiles ok on MinGw:
#include <vector>
class uncopiable {
using self = uncopiable;
protected:
uncopiable() {}
~uncopiable() {}
uncopiable(const self&) = delete;
self& operator=(const self&) = delete;
};
struct A {
struct B : uncopiable {
using self = B;
B() {
}
B(B&&) {};
self& operator=(B&&) = default;
~B() {
}
};
A() { v.emplace_back(); }
~A() {}
private:
std::vector<B> v;
};
int main () {
A* a = new A();
}
The section N3797::12.8/11 [class.copy] says:
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:
[...]
— a non-static data
member of class type M (or array thereof) that cannot be copied/moved
because overload resolution (13.3), as applied to M’s corresponding
constructor, results in an ambiguity or a function that is deleted or
inaccessible from the defaulted constructor
The first case about the ambiguity of corresponding copy/move constructor is quite clear. We can write the following:
#include <iostream>
using namespace std;
struct A
{
A(){ }
A(volatile A&){ }
A(const A&, int a = 6){ }
};
struct U
{
U(){ };
A a;
};
U u;
U t = u;
int main(){ }
to reflect that. But what about or a function that is deleted or inaccessible from the defaulted constructor? What's that got with a function inaccessible from the default constructor? Could you provide an example reflecting that?
Simply put:
struct M { M(M const&) =delete; };
struct X { X(X const&) =default; M m; }; // X(X const&) is actually deleted!
Implicitly-declared functions are also considered "defaulted" ([dcl.fct.def.default] / 5); a more familiar pre-C++11 example might be something like:
struct M { protected: M(M const&); };
struct X { M m; }; // X's implicit copy constructor is deleted!
Note that if you explicitly default the function after it has been declared, the program is ill-formed if the function would be implicitly deleted ([dcl.fct.def.default] / 5):
struct M { M(M const&) =delete; };
struct X { X(X const&); M m; };
X::X(X const&) =default; // Not allowed.
a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor
The wording is perhaps slightly contrived, for conciseness most certainly. The idea, as emphasised in the above, is that the function in question is the M copy constructor being overloaded in way which renders it inaccessible. So having a member of class M whose copy constructor is made protected for instance would delete the copy constructor of X. Likewise, simply deleting the copy constructor of M would have the same result.
Is this
struct Example {
string a, b;
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
Example& operator=(Example&& mE) { a = move(mE.a); b = move(mE.b); return *this; }
}
equivalent to this
struct Example {
string a, b;
Example(Example&& mE) = default;
Example& operator=(Example&& mE) = default;
}
?
Yes both are the same.
But
struct Example {
string a, b;
Example(Example&& mE) = default;
Example& operator=(Example&& mE) = default;
}
This version will permits you to skip the body definition.
However, you have to follow some rules when you declare explicitly-defaulted-functions :
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
A function definition of the form:
attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ;
is called an explicitly-defaulted definition. A function that is explicitly defaulted shall
be a special member function,
have the same declared function type (except for possibly differing ref-qualifiers and except that in the case of a copy constructor or copy assignment operator, the parameter type may be “reference to non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared,
not have default arguments.
Is a =default move constructor equivalent to a member-wise move constructor?
Yes. Update: Well, not always. Look at this example:
#include <iostream>
struct nonmovable
{
nonmovable() = default;
nonmovable(const nonmovable &) = default;
nonmovable( nonmovable &&) = delete;
};
struct movable
{
movable() = default;
movable(const movable &) { std::cerr << "copy" << std::endl; }
movable( movable &&) { std::cerr << "move" << std::endl; }
};
struct has_nonmovable
{
movable a;
nonmovable b;
has_nonmovable() = default;
has_nonmovable(const has_nonmovable &) = default;
has_nonmovable( has_nonmovable &&) = default;
};
int main()
{
has_nonmovable c;
has_nonmovable d(std::move(c)); // prints copy
}
It prints:
copy
http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb
You declared defaulted move constructor, but copying happens instead of moving. Why? Because if a class has even a single non-movable member then the explicitly defaulted move constructor is implicitly deleted (such a pun). So when you run has_nonmovable d = std::move(c), the copy constructor is actually called, because the move constructor of has_nonmovable is deleted (implicitly), it just doesn't exists (even though you explicitly declared the move constructor by expression has_nonmovable(has_nonmovable &&) = default).
But if the move constructor of non_movable was not declared at all, the move constructor would be used for movable (and for every member that has the move constructor) and the copy constructor would be used for nonmovable (and for every member that does not define the move constructor). See the example:
#include <iostream>
struct nonmovable
{
nonmovable() = default;
nonmovable(const nonmovable &) { std::cerr << "nonmovable::copy" << std::endl; }
//nonmovable( nonmovable &&) = delete;
};
struct movable
{
movable() = default;
movable(const movable &) { std::cerr << "movable::copy" << std::endl; }
movable( movable &&) { std::cerr << "movable::move" << std::endl; }
};
struct has_nonmovable
{
movable a;
nonmovable b;
has_nonmovable() = default;
has_nonmovable(const has_nonmovable &) = default;
has_nonmovable( has_nonmovable &&) = default;
};
int main()
{
has_nonmovable c;
has_nonmovable d(std::move(c));
}
It prints:
movable::move
nonmovable::copy
http://coliru.stacked-crooked.com/a/420cc6c80ddac407
Update: But if you comment out the line has_nonmovable(has_nonmovable &&) = default;, then copy will be used for both members: http://coliru.stacked-crooked.com/a/171fd0ce335327cd - prints:
movable::copy
nonmovable::copy
So probably putting =default everywhere still makes sense. It doesn't mean that your move expressions will always move, but it makes chances of this higher.
One more update: But if comment out the line has_nonmovable(const has_nonmovable &) = default; either, then the result will be:
movable::move
nonmovable::copy
So if you want to know what happens in your program, just do everything by yourself :sigh:
Yes, a defaulted move constructor will perform a member-wise move of its base and members, so:
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
is equivalent to:
Example(Example&& mE) = default;
we can see this by going to the draft C++11 standard section 12.8 Copying and moving class objects paragraph 13 which says (emphasis mine going forward):
A copy/move constructor that is defaulted and not defined as deleted
is implicitly defined if it is odrused (3.2) or when it is explicitly
defaulted after its first declaration. [ Note: The copy/move
constructor is implicitly defined even if the implementation elided
its odr-use (3.2, 12.2). —end note ][...]
and paragraph 15 which says:
The implicitly-defined copy/move constructor for a non-union class X
performs a memberwise copy/move of its bases and members. [ Note:
brace-or-equal-initializers of non-static data members are ignored.
See also the example in 12.6.2. —end note ] The order of
initialization is the same as the order of initialization of bases and
members in a user-defined constructor (see 12.6.2). Let x be either
the parameter of the constructor or, for the move constructor, an
xvalue referring to the parameter. Each base or non-static data member
is copied/moved in the manner appropriate to its type:
if the member is an array, each element is direct-initialized with the corresponding subobject of x;
if a member m has rvalue reference type T&&, it is direct-initialized with static_cast(x.m);
otherwise, the base or member is direct-initialized with the corresponding base or member of x.
Virtual base class subobjects shall be initialized only once by the
implicitly-defined copy/move constructor (see 12.6.2).
apart very pathological cases ... YES.
To be more precise, you have also to considered eventual bases Example may have, with exact same rules. First the bases -in declaration order- then the members, always in declaration order.