When defining a class, is the following valid?
T(const T&&) = default;
I was reading about move constructors here and it explains how the default may still be implicitly declared:
A class can have multiple move constructors, e.g. both T::T(const T&&)
and T::T(T&&). If some user-defined move constructors are present, the
user may still force the generation of the implicitly declared move
constructor with the keyword default.
At the bottom of the page it mentions defect report CWG 2171:
CWG 2171 C++14
X(const X&&) = default was non-trivial, made trivial.
Maybe the wiki entry just has a mistake and CWG 2171 is only referring to a copy constructor, not a move constructor?
From the n4296 draft:
8.4.2.1 Explicitly-defaulted functions:
A function that is explicitly defaulted shall
(1.1) — be a special member function,
(1.2) — 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, and
(1.3) — not have default arguments.
12.8.10 Copying and moving class objects:
The implicitly-declared move constructor for class X will have the form
X::X(X&&)
As a consequence the line:
T(const T&&) = default;
is not valid because the implicitly-declared move constructor has the form of:
T(T&&)
Related
I'm confused on what "default constructors" are because I'm getting two meanings from both my class and also online.
1) We have written a constructor ourselves, but we made the parameters set to default values.
2) We have NOT written ANY construct at all, but we can still "pretend" like we did and initialize an instance of a class using a C++ "provided constructor"
If the case is #2, what happens when you initialize? Garbage values?
Thanks!
[class.ctor]/4:
A default constructor for a class X is a constructor of class X
for which each parameter that is not a function parameter pack has a
default argument (including the case of a constructor with no
parameters). If there is no user-declared constructor for class X, a
non-explicit constructor having no parameters is implicitly declared
as defaulted ([dcl.fct.def]). An implicitly-declared default
constructor is an inline public member of its class.
If you do not provide any constructors, then C++ will synthesize a (possibly deleted) default constructor. The semantics of this synthesized constructor is specified in [class.ctor]/7:
A default constructor that is defaulted and not defined as deleted is
implicitly defined when it is odr-used to create an object of its class type ([intro.object]) or when it is explicitly defaulted after
its first declaration. The implicitly-defined default constructor
performs the set of initializations of the class that would be
performed by a user-written default constructor for that class with no
ctor-initializer and an empty compound-statement. If that user-written default constructor would be ill-formed, the program is
ill-formed. If that user-written default constructor would satisfy the
requirements of a constexpr constructor, the implicitly-defined
default constructor is constexpr. Before the defaulted default
constructor for a class is implicitly defined, all the
non-user-provided default constructors for its base classes and its
non-static data members shall have been implicitly defined.
[ Note: An implicitly-declared default constructor has an
exception specification ([except.spec]). An explicitly-defaulted
definition might have an implicit exception specification, see
[dcl.fct.def]. — end note ]
Therefore, yes, the data members will be default initialized without an in-class member initializers. This leaves members of builtin types uninitialized.
I could not find where in the standard it is stated that it is forbidden to explicitly default a copy-constructor and copy-assignment with a volatile& or const volatile& argument, like this:
struct A{
A(const volatile A&) =default; // fails to compile on (all) compilers
};
In [dcl.fct.def.default] there is no such a restriction, while [class.copy] specifies that A(const volatile A&) is a copy constructor.
Note: I am just looking for the location in the text of the standard which specifies this behavior.
You are in the right sections, but are overlooking some crucial bullets.
[dcl.fct.def.default]/1:
A function definition of the form:
...
is called an explicitly-defaulted definition. A function that is
explicitly defaulted shall
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, and
[class.copy.ctor]/7:
The implicitly-declared copy constructor for a class X will have the
form
X::X(const X&)
if each potentially constructed subobject of a class type M (or array
thereof) has a copy constructor whose first parameter is of type const
M& or const volatile M&.119 Otherwise, the implicitly-declared copy
constructor will have the form
X::X(X&)
...
119) This implies that the reference parameter of the implicitly-declared copy constructor cannot bind to a volatile lvalue;
When the above is summed up, your only two options for explicitly defaulting a copy c'tor are these:
struct A {
A(const A&) = default;
};
struct B {
B(B&) = default;
};
When the standard says A(const volatile A&) is a copy constructor. It means that a user-provided c'tor with such a parameter can be the classes copy c'tor.
Per this presentation, if either the copy constructor or copy assignment operator is "user declared", then no implicit move operations will be generated. Does deleteing the copy constructor or copy assignment operator count as "user declared"?
struct NoCopy {
NoCopy(NoCopy&) = delete;
NoCopy& operator=(const NoCopy&) = delete;
};
Will implicit move operations be generated for the NoCopy class? Or does deleting the relevant copy operations count as "user declared" and thus inhibit implicit move generation?
If possible, I'd prefer an answer referencing the relevant parts of the standard.
According to slide 14 of your presentation, a deleted copy constructor is "user declared" thus inhibiting the move generation.
The term "user declared" doesn't have a formal definition in the standard. It is meant to be the opposite of "implicitly declared" in the context of special member functions. [dcl.fct.def.default]/4 could be a bit clearer about this fact, but the intention is there:
Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (12.1 12.4, 12.8), which might mean defining them as deleted. A special member 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.
Both NoCopy(NoCopy&) = delete; and NoCopy& operator=(const NoCopy&) = delete; are declarations of special member functions. Since you are explicitly declaring them, as opposed to allowing the compiler to declare them implicitly, they are user-declared. Those declarations will therefore suppress the implicit declarations of the move constructor and move assignment operator per [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.
In C++98, the C++ compiler could automatically generate copy constructor and copy assignment operator via member-wise copy, e.g.
struct X {
std::string s;
std::vector<int> v;
int n;
};
The compiler automatically generates copy constructor and copy assignment operator for X, using member-wise copy.
But how do things change in C++11 with move semantics?
Are the move constructor and move assignment operator automatically generated, like copy constructors and copy assignment operators?
Are there cases in which move operations are not automatically generated?
Nikos Athanasiou gave a good answer but I wanted to add this tool that I think is very useful.
Here is a screenshot of Howard Hinnant's presentation "Everything You Ever Wanted To Know About Move Semantics (and then some)" from ACCU 2014 conference which I think is a very good reminder of the rules of automatic generation of special members:
Clarification from Mr Hinnant from the comments:
The slide doesn't say it, but the red squares indicate deprecated
behavior. I.e. if you don't want to depend upon deprecated behavior,
then declare both of your copy members if you declare your destructor,
or one of the copy members (basically follow the C++98/03 "rule of 3")
I recommend reading the slides to get the progressive construction of this table and have a detailed explanation of how and why we have this now.
Other presentations can be found there: http://accu.org/index.php/articles/1901
From the standard Ch. 12 - Special member functions
Par 12.8 Copying and moving class objects (emphasis mine)
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.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that
otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]
Then 11 explains the rules for deleting the defaulted move constructor
11 . 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 variant member with a non-trivial corresponding constructor and X is a union-like class,
— 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,
— a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
— 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,
— 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).
[ Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. —end note ]
On the complexity of it all *
The rules can be somewhat overwhelming. It's good to use some technique to bypass the complexity. Examples are :
Make use of the rule of zero to simplify the writing of the majority of your classes.
(On implicitly deleted) Explicitly default the special member function in question; if it would have been implicitly defined as deleted, the compiler will complain.
* points made in the comments by myself (1) and dyp (2)
It seems that a vector will check if the move constructor is labeled as noexcept before deciding on whether to move or copy elements when reallocating. Is the default move constructor defined as noexcept? I saw the following documentation but it didn't specify this.http://en.cppreference.com/w/cpp/language/move_constructor
Implicitly-declared move constructor
If no user-defined move
constructors are provided for a class type (struct, class, or union),
and all of the following is true: there are no user-declared copy
constructors there are no user-declared copy assignment operators
there are no user-declared move assignment operators there are no
user-declared destructors the implicitly-declared move constructor is
not defined as deleted due to conditions detailed in the next section
then the compiler will declare a move constructor as an 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&&).
If some user-defined move constructors are present, the user may still
force the generation of the implicitly declared move constructor with
the keyword default.
I think the answer is 15.4/14 (Exception specifications):
An inheriting constructor (12.9) and an implicitly declared special member function (Clause 12) have an exception-specification. If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification
of a function directly invoked by f’s implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.
Basically, it Does What You Think, and the implicitly-declared move constructor is noexcept whenever it can be.