Consider the following classes.
struct with_copy {
with_copy() = default;
with_copy(with_copy const&) {}
with_copy& operator=(with_copy const&) { return *this; }
};
struct foo {
with_copy c;
std::unique_ptr<int> p;
};
with_copy
have a copy constructor? Yes. It was explicitly defined.with_copy
have a move constructor? No. The explicit copy constructor prevents it from being generated.with_copy
have a deleted move constructor? No. Not having a move constructor is not the same as having a deleted one. A deleted move constructor would make an attempt to move ill-formed instead of degenerating to a copy.with_copy
copyable? Yes. Its copy constructor is used for copies.with_copy
movable? Yes. Its copy constructor is used for moves.... and now the tricky ones.
foo
have a copy constructor? Yes. It has a deleted one, as its defaulted definition would be ill-formed due to invoking unique_ptr
's deleted copy constructor.foo
have a move constructor? GCC says yes, clang says no.foo
have a deleted move constructor? Both GCC and clang say no.foo
copyable? No. Its copy constructor is deleted.foo
movable? GCC says yes, clang says no.(The behaviour is similar when one considers assignment instead of construction.)
As far as I can see, GCC is correct. foo
should have a move constructor that performs a move on each member, which in with_copy
's case degenerates to a copy. Clang's behaviour seems quite ridiculous: I have an aggregate with two movable members, and yet my aggregate is an immovable brick.
Who's right?
there is no user-declared destructor . then the compiler will declare a move constructor as a non- explicit inline public member of its class with the signature T::T (T&&). A class can have multiple move constructors, e.g. both T::T(const T&&) and T::T(T&&).
Trivial move constructor. A trivial move constructor is a constructor that performs the same action as the trivial copy constructor, that is, makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially movable.
The copy constructors in C++ work with the l-value references and copy semantics (copy semantics means copying the actual data of the object to another object rather than making another object to point the already existing object in the heap).
Prerequisites: l-value and r-value references in C++, Copy Constructor in C++. What is a Move Constructor? The copy constructors in C++ work with the l-value references and copy semantics (copy semantics means copying the actual data of the object to another object rather than making another object to point the already existing object in the heap).
C++11, or rather n3485, [class.copy]/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.
and /11:
An implicitly-declared copy/move constructor is an
inline public
member of its class. A defaulted copy/ move constructor for a classX
is defined as deleted (8.4.3) ifX
has:
- [...]
- for the copy constructor, a non-static data member of rvalue reference type, or
- for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.
As with_copy
is not trivially copyable, foo
will have no move-constructor (it would be defined as deleted, therefore it won't be implicitly declared).
C++1y, or rather github repo commit e31867c0 from 2013-11-12; incorporating DR1402:
/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, andX
does not have a user-declared destructor.
and /11:
An implicitly-declared copy/move constructor is an
inline public
member of its class. A defaulted copy/ move constructor for a classX
is defined as deleted (8.4.3) ifX
has:
- [...]
- for the copy constructor, a non-static data member of rvalue reference type.
A defaulted move constructor that is defined as deleted is ignored by overload resolution (13.3, 13.4).
Here, foo
will have a move-constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With