N4296::12.8/11 [class.copy] told us the following:
A defaulted copy/move constructor for a class X is defined as deleted
(8.4.3) if X has:
[...]
(11.2) — a potentially constructed subobject 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
[...]
So it's not clear why the program
struct X
{
};
struct Y
{
X&& x;
Y(Y const&)= default;
};
int main() { }
DEMO
works fine, but the following:
struct X
{
};
struct Y
{
X&& x;
Y(Y const&);
};
Y::Y(Y const&)= default; //error
int main() { }
DEMO
[dcl.fct.def.default]/p5, emphasis mine:
A function is user-provided if it is user-declared and not
explicitly defaulted or deleted on its first declaration. A
user-provided explicitly-defaulted function (i.e., explicitly
defaulted after its first declaration) is defined at the point where
it is explicitly defaulted; if such a function is implicitly defined
as deleted, the program is ill-formed.
This makes sense as any use of a deleted function should render a program ill-formed, but with a user-provided explicitly-defaulted function, it may be impossible to diagnose this at the call site:
// y.h
struct X
{
};
struct Y
{
X&& x;
Y(Y const&);
};
// y.cpp
#include "y.h"
Y::Y(Y const&)= default; //defined as deleted
// main.cpp
#include "y.h"
int main() {
Y y = Y();
}
When compiling main.cpp, the compiler has no idea about Y's copy constructor other than that it exists; it doesn't know that it's defaulted, and can't possibly diagnose that it is actually deleted. The only place such a error can be diagnosed is where the function is explicitly defaulted.
Related
One can see in the snippet below, that the user-declared move constructor is called to initialize the objects yand z of type X. See live-example.
#include <iostream>
struct X{
X(){}
X(X&&) = default;
// X(X&);
// X& operator=(const X& x);
// ~X() = default;
};
X f() { X x; return x; }
X y = f();
X z = X();
int main(){}
Now, if we comment out the declaration of this move constructor, the code continues to execute without a problem, with the implicitly declared move constructor. And this is OK.
#include <iostream>
struct X{
X(){}
// X(X&&) = default;
// X(X&);
// X& operator=(const X& x);
// ~X() = default;
};
X f() { X x; return x; }
X y = f();
X z = X();
int main(){}
Now, let's uncomment below the declaration of the copy constructor X(X&);. As we can see in the next live-example, the code doesn't compile, because the move constructor is not implicitly generated by the compiler. And this is correct according to bullet point (9.1) of §12.8/9 (N4140).
#include <iostream>
struct X{
X(){}
// X(X&&) = default;
X(X&);
// X& operator=(const X& x);
// ~X() = default;
};
X f() { X x; return x; }
X y = f();
X z = X();
int main(){}
The problem seems to start now, when we comment out again the declaration of the copy constructor and uncomment the declaration of the copy assignment operator (see below). Now we have a user-declared copy assignment operator and according to bullet point (9.2) in §12.8/9 the code should not compile. But it does, in clang and GCC.
#include <iostream>
struct X{
X(){}
// X(X&&) = default;
// X(X&);
X& operator=(const X& x);
// ~X() = default;
};
X f() { X x; return x; }
X y = f();
X z = X();
int main(){}
The same happens when we comment out again the declaration for the copy assignment operator and uncomment the declaration for the default destructor. Again, according to bullet point (9.4) in §12.8/9 the code should not compile, but it does in clang and GCC.
I may be missing something here, but I just don't know where did I fail in my exposition above.
The code compiles in the last sample not because of any implicit move constructor or move assignment but because a copy constructor is generated of the form;
X(X const&);
Which happily binds to the temporary.
In your third sample, the code fails to compile (not related to move) because you have a copy constructor X(X&);, but it is of an inappropriate form to bind to the temporary, it would need to be X(X const&);. Temporaries can bind to const references.
I believe the compilers are correct.
This code:
#include <iostream>
struct X{
X(){}
X& operator=(const X& x);
};
X f() { X x; return x; }
X y = f();
X z = X();
int main(){}
is perfectly fine. [class.copy] does say:
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 [...] X does not have a user-declared copy assignment operator, [...]
As a result, X will not have an implicitly defaulted move constructor. However, note that the alternative is not a deleted move constructor. Simply a non-existent one. If the implicitly-declared move constructor were deleted, then the code would fail to compile. But that is not the case here.
But what does it say about the 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.
X has neither a move constructor nor move assignment operator, so X has an implicitly-declared defaulted copy constructor. This case is deprecated, but still valid code. It is likely that in some future standard it will be well-formed, but not yet!
As a result, our X really is:
struct X{
X(){}
X(const X&) = default;
X& operator=(const X& x);
};
and the expression X y = f(); copy-initializes y. It cannot move-initialize y, since we have no move constructor, but the copy constructor is still a match for X.
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.
Code:
struct A
{
~A(){ };
};
A::A(){ }; //error: definition of implicitly declared default constructor
int main()
{
A a;
}
DEMO
Why does the code produces the error? I expected that the program compiles fine. The Standard says N3797::12.8/7 [class.copy]:
If the class definition does not explicitly declare a copy
constructor, 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.
It's a bug or my misunderstanding?
struct A
{
~A(){ };
A();
};
A::A(){ }; //here you can define default constructor
int main()
{
A a;
}
you have defined explicit destructor not constructor , add constructor declarartion and define it as outside clas
You may not define an implicitly declared constructor by the compiler.
From the C++ Standard (12 Special member functions)
... Programs shall not define implicitly-declared special member functions
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.
Why the output is 0003212 ?
#include <iostream>
using namespace std;
template<typename X> class C
{
public:
C() { cout<<"0";}
template<class T> C(const C<T>& c) { cout<<"1";}
C(const C<int>& c) { cout<<"2";}
template<class T> C(const C<T*>& c) { cout<<"3";}
};
int main(int argc, char* args[])
{
C<int> c1; // 0
C<double> c2; // 0
C<int*> c3; // 0
C<int> c4(c3); // 3
C<int> c5(c1); // 2
C<int> c6(c2); // 1
C<float> c7(c1); // 2
C<double> c8(c2); // ?
std::cin.get();
return 0;
}
What is invoked in the last meaning line?
I can suppose that it's some auto-created ctor
but can't figure out which one.
There are several C++ language rules in play here.
A template cannot be a copy constructor. (Standard rule 12.8p2)
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments.
If no copy constructor is defined, the compiler generates a default one (if possible). (Standard rule 12.8p7)
If the class definition does not explicitly declare a copy constructor, 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. Thus, for the class definition
struct X {
X(const X&, int);
};
a copy constructor is implicitly-declared. If the user-declared constructor is later defined as X::X(const X& x, int i =0) { /∗ ... ∗/ }
then any use of X's copy constructor is ill-formed because of the ambiguity; no diagnostic is required.
If a template and non-template are an equally good match for the arguments, the non-template wins. (Standard rule 13.3.3) The rule is a big hard-to-digest mess, I'll show just the important part:
[...] a viable function F1 is defined to be a better function than another viable function F2 if [...rules about argument matching...] or, if not that, F1 is a non-template function and F2 is a function template specialization [...]
From the code you provided, only
C<int>::C(const C<int>&)
is a user-defined copy-constructor that prints 2. All X other than int don't define a copy-constructor, so the compiler creates one.
See also
Templated copy-constructor fails with specific templated type
and
initialization ignores constructor templates
It's copy constructor generated for you by compiler, and since it's best match it's selected in last case.
In last case you call default copy constructor.