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.
Related
I want to refresh my memory on the conditions under which a compiler typically auto generates a default constructor, copy constructor and assignment operator.
I recollect there were some rules, but I don't remember, and also can't find a reputable resource online. Can anyone help?
In the following, "auto-generated" means "implicitly declared as defaulted, but not defined as deleted". There are situations where the special member functions are declared, but defined as deleted.
The default constructor is auto-generated if there is no user-declared constructor (§12.1/5).
The copy constructor is auto-generated if there is no user-declared move constructor or move assignment operator (because there are no move constructors or move assignment operators in C++03, this simplifies to "always" in C++03) (§12.8/8).
The copy assignment operator is auto-generated if there is no user-declared move constructor or move assignment operator (§12.8/19).
The destructor is auto-generated if there is no user-declared destructor (§12.4/4).
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 (§12.8/10).
The move assignment operator is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move assignment operator is valid (e.g. if it wouldn't need to assign constant members) (§12.8/21).
I've found the diagram below very useful.
from Sticky Bits - Becoming a Rule of Zero Hero
C++17 N4659 standard draft
For a quick cross standard reference, have a look at the "Implicitly-declared" sections of the following cppreference entries:
https://en.cppreference.com/w/cpp/language/copy_constructor
https://en.cppreference.com/w/cpp/language/move_constructor
https://en.cppreference.com/w/cpp/language/copy_assignment
https://en.cppreference.com/w/cpp/language/move_assignment
The same information can of course be obtained from the standard. E.g. on C++17 N4659 standard draft:
15.8.1 "Copy/move constructors" says for for copy constructor:
6 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.
and for move constructor:
8 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
(8.1)
— X does not have a user-declared copy constructor,
(8.2)
— X does not have a user-declared copy assignment operator,
(8.3)
— X does not have a user-declared move assignment operator, and
(8.4)
— X does not have a user-declared destructor.
15.8.2 "Copy/move assignment operator" says for copy assignment:
2 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 (11.4). The latter
case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
and for move assignment:
4 If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly
declared as defaulted if and only if
(4.1) — X does not have a user-declared copy constructor,
(4.2) — X does not have a user-declared move constructor,
(4.3) — X does not have a user-declared copy assignment operator, and
(4.4) — X does not have a user-declared destructor.
15.4 "Destructors" says it for destructors:
4 If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (11.4). An
implicitly-declared destructor is an inline public member of its class.
I want to refresh my memory on the conditions under which a compiler typically auto generates a default constructor, copy constructor and assignment operator.
I recollect there were some rules, but I don't remember, and also can't find a reputable resource online. Can anyone help?
In the following, "auto-generated" means "implicitly declared as defaulted, but not defined as deleted". There are situations where the special member functions are declared, but defined as deleted.
The default constructor is auto-generated if there is no user-declared constructor (§12.1/5).
The copy constructor is auto-generated if there is no user-declared move constructor or move assignment operator (because there are no move constructors or move assignment operators in C++03, this simplifies to "always" in C++03) (§12.8/8).
The copy assignment operator is auto-generated if there is no user-declared move constructor or move assignment operator (§12.8/19).
The destructor is auto-generated if there is no user-declared destructor (§12.4/4).
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 (§12.8/10).
The move assignment operator is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move assignment operator is valid (e.g. if it wouldn't need to assign constant members) (§12.8/21).
I've found the diagram below very useful.
from Sticky Bits - Becoming a Rule of Zero Hero
C++17 N4659 standard draft
For a quick cross standard reference, have a look at the "Implicitly-declared" sections of the following cppreference entries:
https://en.cppreference.com/w/cpp/language/copy_constructor
https://en.cppreference.com/w/cpp/language/move_constructor
https://en.cppreference.com/w/cpp/language/copy_assignment
https://en.cppreference.com/w/cpp/language/move_assignment
The same information can of course be obtained from the standard. E.g. on C++17 N4659 standard draft:
15.8.1 "Copy/move constructors" says for for copy constructor:
6 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.
and for move constructor:
8 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
(8.1)
— X does not have a user-declared copy constructor,
(8.2)
— X does not have a user-declared copy assignment operator,
(8.3)
— X does not have a user-declared move assignment operator, and
(8.4)
— X does not have a user-declared destructor.
15.8.2 "Copy/move assignment operator" says for copy assignment:
2 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 (11.4). The latter
case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
and for move assignment:
4 If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly
declared as defaulted if and only if
(4.1) — X does not have a user-declared copy constructor,
(4.2) — X does not have a user-declared move constructor,
(4.3) — X does not have a user-declared copy assignment operator, and
(4.4) — X does not have a user-declared destructor.
15.4 "Destructors" says it for destructors:
4 If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (11.4). An
implicitly-declared destructor is an inline public member of its class.
The question is as my title states.
I'm asking because I have a class with a defaulted move constructor but code trying to perform copy assignment is failing stating that the copy assignment operator is deleted (according to Visual Studio 2015).
So I checked the rules here for implicitly declared copy assignment operators:
The implicitly-declared or defaulted copy assignment operator for class T is defined as deleted in any of the following is true:
...
T has a user-declared move constructor
T has a user-declared move assignment operator
So basically I'm not sure if a defaulted move constructor counts as user-declared. My gut tells me yes but when it comes to standardese I always like to be sure since assumptions can be costly.
The standard says:
12.8 Copying and moving class objects [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.
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 (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.
Your class has defaulted move constructor, but it is explicitly declared.
So according to standard implicitly declared copy constructor and copy assignment operator is defined as deleted.
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
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 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.
Using this terminology your move constructor is user-declared, but not user-provided.
A defaulted special member function is user-declared but it is also defined by the user as defaulted. The standard doesn't explicitly define the term "user-declared" but it essentially means any special member function that has to be written out by the user. So the following declares a constructor and defines it as defaulted.
struct X {
X() = default; // declaration and definition
};
Defining a member function as defaulted means the definition is equivalent to the implicit definition. It is user-declared by virtue of the fact that it had to be typed out by the user.
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)