What are the rules for automatic generation of move operations?
Asked Answered
W

2

42

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?

Wheelchair answered 21/6, 2014 at 15:12 Comment(5)
automatic moving is an optimization, and as such should ideally not affect any observable behavior other than speed. but e.g. a user defined destructor may rely on various assumptions about data members. scott meyers once started a long discussion about that in clc++ and subsequently in comp.std.c++, and the current rules (which I'm quite unclear on) reflect that discussion.Chris
If you like graphical, tabular results, slide 28 from github.com/HowardHinnant/presentations/blob/master/accu_2014/… (there have been reports that this does not display well with some pdf readers, if that is the case, try another one).Saldana
@HowardHinnant: Your slides seem great. I will have a more detailed look. Thanks for sharing.Wheelchair
@HowardHinnant: If you may want to write an answer with your slides linked, I'd be happy to upvote that.Wheelchair
Visual Studio 2010-2013 does not generate them, period. From Support For C++11/14/17 Features on MSDN: "Rvalue references v3.0 adds new rules to automatically generate move constructors and move assignment operators under certain conditions. This is implemented in Visual Studio 2015". The "Rvalue references v3.0" they are talking about is N3053, Defining Move Special Member Functions (MARCH 2010).Gabfest
N
77

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:

enter image description here

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

Nerissa answered 1/7, 2014 at 14:32 Comment(5)
+1, and info: 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").Saldana
@HowardHinnant Thanks for the clarification, I added it in the answer.Nerissa
@HowardHinnant Given the deprecated functionality (in red), what will those members become once the functionality is removed? Will the be "not declared" or "deleted"?Pizzicato
@Niall: I don't know. I don't even have a good guess. I think either of the options you mention is possible. Today, the most likely guess is that they will never be removed. Today compilers are even reluctant to turn this deprecated warning on by default. I'm trying to do my small part in reversing that trend through education. I think eventual removal by whatever option is a good direction.Saldana
this would make a nice posterRoentgenotherapy
R
31

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 :

  1. Make use of the rule of zero to simplify the writing of the majority of your classes.
  2. (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)

Roentgenotherapy answered 21/6, 2014 at 15:22 Comment(6)
These seem to be the post-CWG-1402 rules; although those are "better" since many compiler vendors will use those for their C++11 modes, those rules are not "from the standard".Rampageous
@Wheelchair Rules are pretty much always complex. I like the rule of zero - if I have to stray from it, I have to keep the related Standard page open (I'm still insecure on implicitly declared special member functions)Roentgenotherapy
You can explicitly default them; if they would have been implicitly defined as deleted, the compiler will complain.Rampageous
@Rampageous Loving the witty shortcut . Awesome !! I mean C++ doesn't need more rules, it needs this kind of thinking so that knowledge can be maintainable, or else it'll get out of hand (IMHO)Roentgenotherapy
Note that you still have to think about what the implicitly-defined version does. I.e. there's a difference between not being implicitly declared and being implicitly defined as deleted.Rampageous
Visual Studio 2010-2013 does not generate them, period. From Support For C++11/14/17 Features on MSDN: "Rvalue references v3.0 adds new rules to automatically generate move constructors and move assignment operators under certain conditions. This is implemented in Visual Studio 2015". The "Rvalue references v3.0" they are talking about is N3053, Defining Move Special Member Functions (MARCH 2010).Gabfest

© 2022 - 2024 — McMap. All rights reserved.