类组件的初始化顺序

发布于 2024-11-17 09:55:18 字数 332 浏览 6 评论 0原文

class D: A
{
    B obj;
    C obj2;
}

这里的构造顺序是保证的?

我知道 D 将在 A、B 和 C 之后构造,但我真正想知道的是 A 是否保证在 B 或 C 之前构造,甚至 B 是否保证 在 C 之前构建。

我知道你可以有一个显式的初始化列表:

D(): A(), B(), C()
{}

但是该初始化列表是否确定初始化的顺序

另外,是否有任何组件有或没有默认构造函数?

class D: A
{
    B obj;
    C obj2;
}

What order of construction here is guaranteed?

I know that D will be constructed after A, B and C, but what I really want to know is whether A is guaranteed to be constructed before B or C, or even whether B is guaranteed to be constructed before C.

I know you can have an explicit initialiser list:

D(): A(), B(), C()
{}

but does that initialiser list determine the order of initialisation?

Also, does whether or not any of the components do or don't have a default constructor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萌化 2024-11-24 09:55:18

来自 C++03 标准 ISO/IEC 14882:2003(E) §12.6.2/5 [class.base.init]:

初始化应按以下顺序进行:
— 首先,并且仅对于如下所述的最派生类的构造函数,虚拟基类应按照它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中“从左到右”是派生类中基类名称的出现顺序base-specifier-list
- 然后,直接基类应按照它们出现在base-specifier-list中的声明顺序进行初始化(无论mem-initializers的顺序如何)。
— 然后,非静态数据成员应按照它们在类定义中声明的顺序进行初始化(同样无论 mem-initializers 的顺序如何)。
— 最后,执行构造函数的主体。
[注意:声明顺序必须确保基类和成员子对象以与初始化相反的顺序销毁。 ]

因此,在这种情况下,可以保证初始化的顺序首先是基类 A,然后是子对象 B(因为它首先出现在类列表中)类定义中的成员),然后是子对象C。初始化器列表的顺序无关紧要,就像任何成员是否具有默认构造函数一样 - 如果成员没有默认构造器并且未在初始化器列表中显式初始化,则它具有未指定的值。

From the C++03 standard ISO/IEC 14882:2003(E) §12.6.2/5 [class.base.init]:

Initialization shall proceed in the following order:
— First, and only for the constructor of the most derived class as described below, virtual base classes shall be 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 class names in the derived class base-specifier-list.
— Then, direct base classes shall be initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
— Then, nonstatic data members shall be initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
— Finally, the body of the constructor is executed.
[Note: the declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. ]

So in this case, you are guaranteed that the order of initialization will be first the base class A, then the subobject B (since it appears first in the list of class members in the class definition), then the subobject C. The order of the initializer list is irrelevant, as is whether or not any of the members do or do not have a default constructor—if a member does not have a default constructor and it is not explicitly initialized in an initializer list, then it has an unspecified value.

烟酉 2024-11-24 09:55:18

但是初始化列表是否决定了初始化的顺序?

。初始化列表确定成员数据和基本子对象的初始化顺序。成员按照其声明的顺序进行初始化,并且基子对象按照其提及的顺序进行构造 - 从左到右:

struct A : B, C {}  //B is constructed before C

此外,基子对象是在成员数据初始化之前构造的。

struct A : B, C 
{
      D d;
      E e;
};

上述结构中的初始化顺序:

    B     =>    C      =>   d    =>   e   
subobject   subobject     member    member

并且它们以相反的顺序被破坏。

but does that initialiser list determinethe ORDER of initialisation?

No. Initialization-list doesn't determine the the order of initialization of member data and the base subobject(s). Members are initialized in order of their declaration, and base subobjects are constructed in the order of their mention - from left to right:

struct A : B, C {}  //B is constructed before C

Also, the base subobjects are constructed before the initialization of the member data.

struct A : B, C 
{
      D d;
      E e;
};

Order of initialization in the above struct:

    B     =>    C      =>   d    =>   e   
subobject   subobject     member    member

And they're destructed in the reverse order.

星星的轨迹 2024-11-24 09:55:18

也许这个损坏代码的例子将有助于说明:

如果我像这样定义一个类:

class Connection {

   boost::asio::tcp::ip::socket _socket;
   boost::asio::io_service _io_service;

   Connection() : _io_service(), _socket(_io_service)
   {
   }
};

这在所有现代编译器中都会失败。由于 _socket 首先被定义为类成员,因此初始化列表将首先尝试初始化它,尽管初始化列表要求编译器首先初始化 _io_service。但由于_io_service尚未初始化(socket构造函数依赖于已初始化的_io_service),因此_socket的初始化将导致段错误。

也许有人可以引用规定这种行为的标准的适当部分。

对于问题的后半部分,基类将始终在类自己的成员之前初始化。

Perhaps this example of broken code will help illustrate:

If I define a class like so:

class Connection {

   boost::asio::tcp::ip::socket _socket;
   boost::asio::io_service _io_service;

   Connection() : _io_service(), _socket(_io_service)
   {
   }
};

This will fail in all modern compilers. Because _socket is defined first as a class member, the initialization list will try to initialize it first, despite the fact that the initialization list asks the compiler to initialize _io_service first. But since _io_service has not yet been initialized (the socket constructor depends on an initialized _io_service), the initialization of _socket will cause a segfault.

Perhaps somebody can quote the appropriate section of the standard that dictates this behaviour.

For the second half of the question, base classes will always be initialized before the classes own members.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文