移动派生的构造函数 class

Move constructor for derived class

我有2个类:

template<typename T>
class base{
    T t;
public:
    base(base &&b): t(std::move(b.t)){}
};

template<typename T, typename T2>
class derived : protected base<T>{
    T2 t2;
public:
    derived(derived &&d): base<T>(std::move(d)), t2(std::move(d.t2)){}
};

我将整个 d 对象移动到 derived move-constructor 中以初始化 base 部分并且 d 变得无效但我仍然需要它来使用它t2 初始化部分

这样的事情可以做吗?

我会说你的构造是正确的,除了一点语法错误,你需要在初始化列表中限定 base<T>:

derived(derived &&d): base<T>(std::move(d)), t2(std::move(d.t2)){}

首先,初始化顺序与初始化列表的顺序无关。 n4296 草案在 12.6.2 Initializing bases and members [class.base.init] § 13

中说

In a non-delegating constructor, initialization proceeds in the following order:
(13.1) — First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
(13.3) — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
(13.4) — Finally, the compound-statement of the constructor body is executed.

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note ]

我们也有 §7 或同一章说:

The initialization performed by each mem-initializer constitutes a full-expression. Any expression in a mem-initializer is evaluated as part of the full-expression that performs the initialization.

我的理解是,标准规定在 derived class 的移动构造函数中,事情按以下顺序发生:

  • 调用基 class 的移动构造函数
    • 依次为 T 调用 move ctor 有效地构造 target 的 t 成员并最终将 source 的 t 成员归零
  • 调用了 T2 对象的 move ctor - 在那一刻,还没有到达完整表达式的末尾,最终只有源的 t 个成员被销毁
  • 在完整语句的末尾,源对象处于未确定状态,不应再使用。