考虑这个片段:
struct A
{
A(std::unique_ptr<int> somePtr_)
: somePtr{std::move(somePtr_)},
someInt{*somePtr}
{};
std::unique_ptr<int> somePtr;
const int& someInt;
};
这里,传递并存储unique_ptr
。
然后还会存储对基础数据的引用。
当A
的对象被破坏时,首先someInt
超出范围,然后somePtr
。
IMHO当涉及智能指针时,成员的顺序很重要,不是吗?
但这种设计不是有些脆弱吗?
如果有人更改了会员顺序怎么办?
有没有一个更好/规范的设计,不需要依赖成员顺序,或者它就像RAII一样?
成员的顺序总是很重要的。
智能指针的出现是一种红色的呼啸。示例中的关键在于,一个成员的初始化取决于其他已经初始化的成员。
成员按照它们在类定义中出现的顺序进行初始化。总是
即使在成员初始值设定项列表中以不同的顺序列出它们,它们仍然按照它们在类定义中出现的顺序进行初始化。当顺序不同时,编译器通常会发出警告。
你会遇到类似的问题:
struct foo {
int x;
int y;
foo() : x(1),y(this->x * 2) {}
};
更改x
和y
的顺序将导致初始化未定义(y
将使用未初始化的x
(。
但是这个设计不是有些脆弱吗?
是的。当成员的初始化相互依赖时,您需要格外小心。
如果有人更改了会员顺序怎么办?
您将收到编译器警告,最好不要忽略。
是否有更好的/规范的设计,不需要依赖成员顺序,或者就像RAII一样?
您可能不需要引用和智能指针。除掉其中一个。因为他们都是public
,所以把他们都拥有真的没有意义。
一般来说,评论中的建议可能是一个解决方案。若重构一个成员成为基类的成员,那个么初始化的顺序是毋庸置疑的,因为基类是首先初始化的。