【问题标题】:Is an object fully constructed at the end of the initialiser list?在初始化列表的末尾是否完全构造了一个对象?
【发布时间】:2017-01-20 03:18:43
【问题描述】:

这是 invoking the copy constructor within the constructor 的衍生产品。

我相信一个对象已经完全形成,并且可以预期在初始化列表的末尾表现出这样的行为(编辑:虽然我错了!)。具体来说,成员函数和从构造函数本身访问本地状态的行为将与从任何其他成员函数完全相同。

虽然这似乎是一个有点争议的观点,但另一种选择是,只有在构造函数正常返回后,对象才完全形成。

下面是一个快速而肮脏的测试用例,它显示了初始化列表中提到的所有成员字段正在初始化以及那些没有被默认构造的字段。

#include <cstdio>

struct noise
{
  noise() { printf("noise default constructed\n"); }
  noise(int x) { printf("noise integer constructed %u\n", x); }
  ~noise() { printf("noise dtor\n"); }
};

struct invoke : public noise
{
  noise init;
  noise body;
  invoke() : noise(3), init(4)
  {
    body = noise(5);
    throw *this; // try to use the object before returning normally
  }
  ~invoke() { printf("invoke dtor\n"); }
};

int main()
{
  try
    {
      invoke i;
    }
  catch (...)
    {
    }
}

至少在我的机器上打印,

noise integer constructed 3
noise integer constructed 4
noise default constructed
noise integer constructed 5
noise dtor
noise dtor
noise dtor
noise dtor
invoke dtor
noise dtor
noise dtor
noise dtor

与往常一样,很难区分指定的作品和我的编译器实现的作品!这真的是UB吗?

【问题讨论】:

    标签: c++ language-lawyer


    【解决方案1】:

    在初始化列表的末尾是否完全构造了一个对象?

    不,不是。对象this 在构造函数执行结束时完全构造。

    但是,所有成员都是在初始化列表的末尾构造的。

    区别很细微,但很重要,因为它与析构函数的执行有关。如果this 对象在构造函数执行期间抛出异常,则每个构造的成员和基类都会被破坏。 this 对象的析构函数只有在完全构造后才会执行。

    From the cppreference:

    • 对于任何类或聚合类型的对象,如果它或其任何子对象由普通默认构造函数以外的任何对象初始化,则生命周期在初始化结束时开始。
    • 对于析构函数不平凡的类类型的任何对象,当析构函数开始执行时,生命周期结束。

    【讨论】:

    • 有趣。除了析构函数之外,对象上的函数是否需要完全构造的对象或所有成员都完全构造的对象?
    • 取决于函数,在构造和销毁过程中可以调用普通的成员函数。虚函数有一个问题,它们可能不会调用您期望的实现,并且通常建议不要在构造等期间调用。
    • 这很令人兴奋。谢谢
    【解决方案2】:

    您的示例是明确定义的行为,但仅此而已。

    需要明确的是,我们看到的 "invoke dtor" 行来自您的异常的破坏,而不是顶级 i 对象。

    类的每个成员都在构造函数体开始时被初始化,尽管对象本身在构造函数体完成之前不会被初始化。这就是为什么在顶级调用对象上不调用 ~invoke 的原因。

    throw *this 表达式从*this 复制初始化一个invoke 对象,允许的。 (标准明确规定“成员函数 [...] 可以在构造或销毁期间调用”。)您的复制初始化是默认设置,它只是复制初始化所有已初始化的成员。

    然后因为你的构造函数体通过异常退出,所有初始化的成员都被销毁,异常被传播、捕获、然后处理,调用~invoke,反过来也销毁这些成员。

    【讨论】:

      猜你喜欢
      • 2011-08-07
      • 1970-01-01
      • 1970-01-01
      • 2017-07-20
      • 1970-01-01
      • 2019-11-21
      • 2017-01-19
      • 1970-01-01
      • 2016-01-08
      相关资源
      最近更新 更多