And*_*ack 6 c++ constructor destructor exception-handling c++11
两相结构具有以下形状:
struct something {
something ()
: p1(NULL)
, p2(NULL)
{ }
~something () {
if (p1) delete p1;
if (p2) delete p2;
}
void initialize () {
p1 = new int(2);
p2 = new int(5); // May throw if allocation fails!
}
int* p1;
int* p2;
};
Run Code Online (Sandbox Code Playgroud)
其中一个天真的构造函数(不注意分配失败)将泄漏内存:从不调用部分构造的对象的析构函数.
我的问题:以下代码是安全的,并且通过证据,智能指针是否可以避免两阶段构造?
struct something {
something ()
: p1(new int(2))
, p2(new int(5))
{ }
std::unique_ptr<int> p1;
std::unique_ptr<int> p2;
};
Run Code Online (Sandbox Code Playgroud)
我的问题:以下代码是安全的,
是的,那没关系.
struct something {
something ()
: p(new int(5))
{ }
std::unique_ptr<int> p;
};
Run Code Online (Sandbox Code Playgroud)
注意天真的代码
struct something {
something ()
: p(new int(5))
{ }
int* p;
};
Run Code Online (Sandbox Code Playgroud)
也是例外安全,因为只有一个分配可能会失败.我觉得你在谈论相当
struct something {
something ()
: p(new int(5)), q(new int)
{ }
int *p, *q;
};
Run Code Online (Sandbox Code Playgroud)
哪不会.智能指针也适用于这种情况.
是的,你的新代码很好.但请注意,在更复杂的情况下可能会有微妙的情况:
#include <memory>
struct foo {
foo(std::shared_ptr<int> a, std::shared_ptr<int> b) { }
};
struct bar {
foo f;
bar() : f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int)) { }
};
int main() {
bar b;
}
Run Code Online (Sandbox Code Playgroud)
然而,由于foo初始化列表中构造函数的参数的评估顺序未指定,因此不安全bar.符合标准的编译器可能会选择执行深度或广度的第一个评估顺序(或其他任何东西,只要它们最终都被正确评估).这意味着如果第一个new int成功,但第二个在shared_ptr构造对象之前抛出,则要执行的第一个分配仍然可能泄漏.
如果你发现自己想要做到这一点,那么有两种可能的解决方案,除了回到两阶段构造之外:第一种可能是重构,第二种是shared_ptr首先单独构造s作为bar的成员f.其中哪一项最合适的是我认为需要根据具体情况进行判断.