C++ 子类中的默认移动构造函数

C++ 子类中的默认移动构造函数,c++,c++11,move-semantics,C++,C++11,Move Semantics,在C++11中,如果基类定义了自己的移动(复制)构造函数(赋值运算符),那么它的子类是否需要定义自己的移动(复制)构造函数(赋值运算符),在其中调用基类相应的构造函数/运算符是显式调用的 每次都清楚地定义构造函数、析构函数、移动/复制构造函数(赋值运算符)是一个好主意吗 struct Base { Base() {} Base(Base&& o); }; struct Sub : public Base { Sub(Sub&& o) ;

在C++11中,如果基类定义了自己的移动(复制)构造函数(赋值运算符),那么它的子类是否需要定义自己的移动(复制)构造函数(赋值运算符),在其中调用基类相应的构造函数/运算符是显式调用的

每次都清楚地定义构造函数、析构函数、移动/复制构造函数(赋值运算符)是一个好主意吗

struct Base {
    Base() {}
    Base(Base&& o);
};

struct Sub : public Base {
    Sub(Sub&& o) ;  // Need I do it explicitly ? If not,what the compiler will do for me
};

如果未在基类中指定默认移动构造函数(例如,存在具有已删除移动构造函数的基类除外),编译器将生成一个默认移动构造函数,但在任何情况下,都应显式调用基类“one”(如果有):

Sub(Sub&& o) : Base(std::move(o))
根据标准()12.8/9,复制和移动类对象[class.copy]:

如果
类X
的定义没有显式声明移动构造函数,则当且仅当

-X没有用户声明的复制构造函数

-X没有用户声明的复制分配运算符

-X没有用户声明的移动分配运算符,并且

-X没有用户声明的析构函数

因此,如果您的
满足上述要求,则默认移动构造函数将隐式声明给您

如前所述,基类不知道任何子类。因此,是否在一个基类中声明移动构造函数对其子类中的移动构造函数的隐式生成没有影响


至于您是否应该显式声明类的构造函数/析构函数等,有一点很好。

不,您没有。我将像默认/复制构造函数一样自动生成


隐式声明的移动构造函数

如果没有为类类型(struct、class或union)提供用户定义的移动构造函数,并且以下所有情况均为真:

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
(until C++14) the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section 
It is not user-provided (meaning, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
T has no virtual member functions
T has no virtual base classes
The move constructor selected for every direct base of T is trivial
The move constructor selected for every non-static class type (or array of class type) member of T is trivial 

T has no non-static data members of volatile-qualified type 
然后编译器将声明一个move构造函数作为其类的内联公共成员,签名为T::T(T&&)

一个类可以有多个移动构造函数,例如T::T(const T&&)和T::T(T&&&)。如果存在一些用户定义的移动构造函数,用户仍然可以强制生成带有关键字default的隐式声明的移动构造函数

您的
结构子
没有用户声明的复制构造函数、复制赋值运算符、移动赋值运算符或析构函数

以及

琐碎的移动构造函数

如果满足以下所有条件,则类T的move构造函数是微不足道的:

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
(until C++14) the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section 
It is not user-provided (meaning, it is implicitly-defined or defaulted), and if it is defaulted, its signature is the same as implicitly-defined
T has no virtual member functions
T has no virtual base classes
The move constructor selected for every direct base of T is trivial
The move constructor selected for every non-static class type (or array of class type) member of T is trivial 

T has no non-static data members of volatile-qualified type 
(从C++14开始)

普通移动构造函数是执行与普通复制构造函数相同操作的构造函数,即,像std::memmove一样复制对象表示。所有与C语言兼容的数据类型(POD类型)都是可移动的

隐式定义的移动构造函数

如果隐式声明的move构造函数既没有被删除也没有被忽略,那么编译器将定义它(即生成并编译函数体)。对于联合类型,隐式定义的move构造函数复制对象表示(如std::memmove)对于非联合类类型(类和结构),移动构造函数使用带有xvalue参数的直接初始化,按照初始化顺序对对象的基成员和非静态成员执行完全成员移动。


Base
的move构造函数并不简单(它是用户定义的)。因此,
Sub
的隐式定义的move构造函数将作为“move构造函数按照初始化顺序对对象的基成员和非静态成员执行完整的成员明智的move,使用带有xvalue参数的直接初始化。”

如果您没有任何移动构造函数,编译器将生成默认的移动构造函数,但并不总是这样(请参见示例)。但是,您不能依赖默认move(或任何其他)构造函数来“做正确的事情”,尤其不能依赖基类move构造函数,因为它不知道任何子类。另外,我要说的是,三法则和零法则是相辅相成的,而不是一个排斥或取代另一个。仅仅因为你可以对某些类遵循零规则,并不意味着你可以(或应该)对所有类都这样做。哦,参考OP(和其他奇怪的)。从实际角度来看,截至目前(2014年),C++11模式下的许多编译器(尤其是MSVC)无法正确生成默认移动构造函数,所以最好总是自己写。@c.r.many?我知道有一个(MSVC)假装是C++11,却没有这个功能。这是如何完美地向前推进的呢
Sub&
是一个右值引用,因此它只会作为右值转发。如果您使用了通用引用和
std::forward
,这将是完美的转发。@0x499602D2如果没有完美的转发,OP的代码将生成一个错误,因为复制构造函数在Base中被隐式删除,我是否遗漏了什么?很抱歉,我明白了您的意思:那里只能传递右值。我同意,从这个术语的意义上讲,这并不是完美的转发。std::move在这里就足够了是的,而且还有对基类引用的隐式转换,因此不需要在
std::move()
中使用显式模板参数。