在初始化程序列表的末尾是否完全构造了一个对象? [英] Is an object fully constructed at the end of the initialiser list?

查看:67
本文介绍了在初始化程序列表的末尾是否完全构造了一个对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是从在构造函数中调用复制构造函数衍生出来的.. >

我相信一个对象已经完全形成,并且可以期望在初始化列表的末尾表现出这样的行为(尽管如此,我错了!).具体来说,成员函数和从构造函数本身内部访问局部状态的行为将与从任何其他成员函数获得的行为完全相同.

尽管这似乎有点争议,但替代方法是,只有构造函数正常返回后,对象才能完全形成.

以下是快速&肮脏的测试用例,其中显示了初始化程序列表中提到的所有成员字段都已初始化,而未构造默认值的成员字段.

#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吗?

解决方案

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

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

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

差异很小,但很重要,因为它与析构函数的执行有关.如果this对象在构造函数执行期间引发异常,则将破坏每个构造的成员和基类. this对象的析构函数仅在完全构造后才会执行.

来自cppreference :

  • 对于任何类型或集合类型的对象或其子对象,如果使用普通的默认构造函数进行初始化,则生存期始于初始化结束.
  • 对于任何析构函数并非无关紧要的类类型对象,生命周期在析构函数开始执行时就结束.

This is a spinoff from invoking the copy constructor within the constructor.

I believe that an object is fully formed and can be expected to behave as such by the end of the initialiser list (edit: I was wrong about this though!). Specifically, member functions and accessing local state from within the constructor itself will behave exactly as they would from any other member function.

This seems to be a slightly contentious point of view though, the alternative is that only once the constructor has returned normally is the object fully formed.

The following is a quick & dirty test case for this which shows all the member fields that are mentioned in the initialiser list being initialised and those that aren't getting default constructed.

#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 (...)
    {
    }
}

This prints, on my machine at least,

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

As always, it's difficult to distinguish works-as-specified from works-as-my-compiler-implemented! Is this actually UB?

解决方案

Is an object fully constructed at the end of the initialiser list?

No it is not. The object this is fully constructed at the end of the execution of the constructor.

However, all the members are constructed by the end of the initializer list.

The difference is subtle but it is important as it relates to the execution of the destructors. Every constructed member and base class is destructed if the this object throws an exception during the execution of the constructor. The destructor of the this object will only execute once it is fully constructed.

From the cppreference:

  • For any object of class or aggregate types if it, or any of its subobjects, is initialized by anything other than the trivial default constructor, lifetime begins when initialization ends.
  • For any object of class types whose destructor is not trivial, lifetime ends when the execution of the destructor begins.

这篇关于在初始化程序列表的末尾是否完全构造了一个对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆