构造函数初始化列出了顺序/分配问题

Joã*_*ela 5 c++ constructor

我的问题很简单,下一个代码是安全的吗?

struct Parent {
    B* _a;
    Parent(B* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

还有两点:

  • 我感兴趣的是将对成员对象的引用传递给父对象.
  • 安全我的意思是_b将分配(及其内存地址),并且无论我使用哪个编译器,此代码都将起作用.

提前致谢.


通过安全澄清我实际上意味着内存地址是有效的,因为我已经知道它没有被初始化.

其他说明
在我的实际代码中,我想将类型的对象存储B为其基类的指针A,如下所示:

struct Parent {
    A* _a;
    Parent(A* a) : _a(a) {}
};

struct Child : public Parent {
    B _b;
    Child() : Parent(&_b),  _b(2){};
};

int main() {
    Child c;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我理解AndreyT正确答案,那是非法的.我想我会尝试以不同的方式做到这一点,因为这种方法很容易出错.(我可能会忘记我无法使用该指针并在我的下一个重构中使用它做一些事情).

AnT*_*AnT 8

在你描述的意义上,是的,它是安全的:内存被分配,将指针传递给父进程是完全正确的.内存Child::_b实际上是整个内存的组成部分Child.它不需要任何明确的额外"分配".到目前为止,Child::Child构造函数被调用,内存显然已经存在.

但是,指针指向的内存只能以有限的方式使用(标准在3.8中描述了什么可以和不能用它做什么),因为它指向的对象尚未初始化.在您的具体示例中,您只需存储指针.那是完全可以的.

但是,例如,如果您想将该指针转换为某种基类类型(假设B有一些基类类型),那么您的代码将是非法的.将指向未初始化对象的指针转换为基类指针是非法的(再次参见3.8).


Jam*_*lis 6

初始化顺序如下:

// Base classes:
Parent(&_b)

// Members:
_b(2)

// Constructor Body:
Child() { }
Run Code Online (Sandbox Code Playgroud)

这是否安全取决于您对"安全"的定义.根据你的定义("它会起作用吗?"),是的,它是安全的.生成对象Child::_b时的生命周期开始Child,因此您可以获取指向它的指针,该指针指向一个对象.但是,在_b初始化之后,即在基类的构造函数Parent返回之后,才能使用指向的值.