ISO/IEC JTC1 SC22 WG21 N2583 = 08-0093 - 2008-03-16
Lawrence Crowl, Lawrence@Crowl.org, crowl@google.com
Exploiting move semantics requires writing a move constructor or a move assignment operator. As these functions have significant common implementations, the ability to specify default implementations for them would improve programmer productivity.
We propose to use the =default
syntax of
N2346
Defaulted and Deleted Functions
to specify a default implementation.
Semantically, the default implementation of the move constructor is a recursive move construction of its subobjects. In the event that there is no move constructor defined for a subobject, the copy constructor will be used instead.
The default implementation of the move assignment operator has the corresponding semantics.
For example,
class Derived : public Base { std::vector<int> vec; std::string name; public: Derived(Derived&& x) : Base(static_cast<Base&&>(x)), vec(static_cast<std::vector<int>&&>(x.vec)), name(static_cast<std::string&&>(x.name)) { } Derived& operator=(Derived&& x) { Base::operator=(static_cast<Base&&>(x)); vec = static_cast<std::vector<int>&&>(x.vec); name = static_cast<std::string&&>(x.name); return *this; } };
There seems to be no reason to require that move constructors and move assignment operators be trivial, and so we do not.
A item of insecurity is the handling of pointer member variables. The insecurity is that the ownership of the indirect object is not readily visible in the source code, and no one default will be appropriate in all cases. The possible approaches are:
The handling of reference member variables has much the same issue, except that pointer approach 3 (null parameter pointer member variables) is not possible for references. Thus, the reference approaches are:
The proposed wording shows changes from an editing draft preliminary to the March 2008 mailing. The base text does not form an officially accepted draft. Earlier drafts have slightly different text.
Note that the edits to section 8.4, 8.4.1 and 8.4.2 are identical in this paper and in N2584 Default Swap Functions.
End the section after paragraph 8.
Add a new section comprising paragraph 9 of the old 8.4 Function definitions [dcl.fct.def].
Split the paragraph into three paragraphs, with the first paragraph containing the introductory sentence, the second paragraph containing the special member discussion, and the third paragraph containing the note and example.
Edit the resulting second paragraph as follows.
Only specialSpecial member functions may be explicitly defaulted, and the implementation shall define them as if they had implicit definitions (12.1, 12.4, 12.8). A special member function that would be implicitly defined as deleted shall not be explicitly defaulted. A special member function is user-provided if it is user-declared and not explicitly defaulted on its first declaration. A user-provided explicitly-defaulted function is defined at the point where it is explicitly defaulted.
Add a new section with the following paragraphs.
A move constructor has no implicit default, but may be explicitly defaulted. The default definition shall move construct its bases and variables, with arguments statically cast to a rvalue references (8.3.2 [dcl.ref]) from the corresponding bases and variables of the move constructor parameter. In the event that a base or variable has no move constructor, the copy constructor is used instead, without the static cast.
A move assignment operator has no implicit default, but may be explicitly defaulted. The default definition shall move assign its bases and variables, with arguments statically cast to a rvalue references (8.3.2 [dcl.ref]) from the corresponding bases and variables of the move assignment operator parameter. In the event that a base or variable has no move assignment operator, the copy assignment operator is used instead, without the static cast.
If pointer approach 1 is adopted, add the following paragraph.
If the default implementation of a move function would move from a pointer variable, the use of the move function default is ill-formed.
If pointer approach 2 is adopted, no additional text is needed.
If pointer approach 3 is adopted, add the following paragraph.
If the default implementation of a move function moves from a pointer variable, the implementation shall assign null to that pointer variable.
If reference approach 1 is adopted, add the following paragraph.
If the default implementation of a move function would move to a reference variable, the use of the move function default is ill-formed.
If reference approach 2 is adopted, add the following paragraph.
If the default implementation of a move assignment operator would move to a reference variable, the use of the move function default is ill-formed.
Add a new section comprising paragraph 10 of the old 8.4 Function definitions [dcl.fct.def].
The working draft currently uses the term "move constructor" but does not define the term. It is unclear where to add the definition, move constructors are not a special member function, but construction is most completely described in Chapter 12 Special member functions [special].
A move constructor is a constructor with a declaration of the form
classname
(
classname&&);
The same issue applies to move assignment operators.
A move assignment operator is an assignment operator with a declaration of the form
classname
& operator=(
classname&&);