初始值设定项列表的顺序(以 C++为单位)



我知道对于非静态成员变量,初始值设定项列表中的计算顺序是根据类中的声明顺序。

考虑以下来自isocpp的示例

#include <iostream>
class Y {
public:
Y();
void f();
};
Y::Y()      { std::cout << "Initializing Yn"<<this<<"n"; }
void Y::f() { std::cout << "Using Yn"<<this<<"n"; }
class X {
public:
X(Y& y);
};
X::X(Y& y) { y.f(); }
class Z {
public:
Z() throw();
protected:
X x_;
Y y_;
};
Z::Z() throw() : y_(), x_(y_) {}
int main()
{
Z z;
return 0;
}

由于 X 的 ctor 需要 Y 的引用,理想情况下,我们必须首先初始化y_;这意味着必须在x_之前声明y_。

我希望上面的程序会给出 seg 错误,但下面是我的 o/p。有人可以对此有所了解吗?

-bash-4.1$ ./a.out
Using Y
0x7fffffffe0c1
Initializing Y
0x7fffffffe0c1

我希望上面的程序会给出 seg 错误,但下面是我的 o/p。

从理论上讲,您的代码受制于未定义的行为。

已为对象分配空间,但尚未初始化。此类对象和指向此类对象的指针可以以有限的方式使用,但在此类对象上调用非静态成员函数会导致未定义的行为。

从 https://timsong-cpp.github.io/cppwp/n3337/basic.life#5:

在以下情况下,程序具有未定义的行为:

(5.1) 该对象将是或曾经是具有非平凡析构函数的类类型,指针用作删除表达式的操作数,

(5.2) 指针用于访问非静态数据成员或调用对象的非静态成员函数,或

您没有看到任何不良行为的最可能原因是Y没有任何成员变量。如果您将成员变量添加到Y并在Y:f()中使用它,您很可能会更容易注意到这个问题。

>
class Z {
public:
Z() throw();
protected:
X x_;
Y y_;
};
Z::Z() throw() : y_(), x_(y_) {}

Z中,您在y_之前声明x_。 因此,无论初始值设定项的顺序如何,x都是在y_之前构造的。

而且,在构造y_之前初始化x_(y_)会产生未定义的行为。


我预计上面的程序会给出 seg 错误

未定义的行为是未定义的。 你不应该期待任何特别的事情。

最新更新