移动派生类的构造函数

时间:2016-06-07 00:59:37

标签: c++ c++11 constructor initialization move-semantics

我有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变为无效,但我仍然需要它来使用它&#39 ; t2初始化

的一部分

有可能做这样的事吗?

1 个答案:

答案 0 :(得分:3)

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

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

首先,初始化顺序与初始化程序列表的顺序无关。草案n4296在 12.6.2初始化基础和成员[class.base.init]§13

中说
  

在非委托构造函数中,初始化按以下顺序进行:
  (13.1) - 首先,仅对最派生类(1.8)的构造函数初始化虚拟基类   它们出现在基类的有向无环图的深度优先从左到右遍历中的顺序,   其中“从左到右”是派生类base-specifier-list中基类出现的顺序。   
(13.2) - 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中   (不管mem-initializers的顺序如何)。   
(13.3) - 然后,非静态数据成员按照在类定义中声明的顺序进行初始化   (再次无论mem-initializers的顺序如何)。   
(13.4) - 最后,执行构造函数体的复合语句。

     

[注意:声明命令的目的是确保基础和成员子对象在销毁中被销毁   初始化的逆序。 - 后注]

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

  

每个mem-initializer执行的初始化构成一个完整表达式。任何   mem-initializer中的表达式被计算为执行初始化的完整表达式的一部分。

我的理解是标准说在derived类的移动ctor中,事情按顺序发生:

  • 调用基类的ctor
    • 反过来调用移动ctor为T有效地构造目标的t成员并最终将t成员归零
  • 调用T2对象的ctor被调用 - 此时,尚未到达完整表达式的结尾,并且只有源成员的t成员最终被销毁
  • 在完整语句的末尾,源对象处于未确定状态,不应再使用。