Boost的make_shared()
函数在尝试创建shared_ptr
时承诺异常安全。
为什么没有等效的make_scoped()
?有没有共同的最佳做法?
以下是来自boost::scoped_ptr
documentation的代码示例,对我来说似乎不安全:
boost::scoped_ptr<Shoe> x(new Shoe);
这行代码将按顺序执行以下三项::
Shoe
Shoe
boost::scoped_ptr<Shoe>
如果Shoe
的构造函数抛出异常,内存将被泄露。 (参见R. Martinho Fernandes回答) scoped_ptr
赢了处理释放因为它尚未构建。
这是疏忽吗?或者有没有我没注意到的解决方案?
答案 0 :(得分:15)
scoped_ptr
早于移动语义,并且在设计上是不可复制的。因此,make_scoped
将无法实现,因为为了从函数返回对象,其类型必须是可移动的或可复制的。
答案 1 :(得分:14)
如果构造函数失败,则不会泄漏内存。这是new
语义的一部分,没有涉及智能指针:
struct Foo { Foo() { throw 23; } };
new Foo(); // no memory leaked
make_shared
提供的额外异常安全性来自于您在表达式中初始化两个shared_ptr
并且两个初始化未按顺序排序,就像这样在函数调用参数中:
struct Bar {
Bar(bool fail) {
if(fail) throw 17;
}
}
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false)));
由于new Bar(true)
,shared_ptr<Bar>(new Bar(true))
,new Bar(false)
和shared_ptr<Bar>(new Bar(false))
的评估之间没有排序,因此可能会发生以下情况:
new Bar(false)
并成功:分配内存; new Bar(true)
被评估并失败:它不会泄漏由此评估产生的内存; 目前尚未构建shared_ptr
,因此#1中分配的内存现已泄露。
答案 2 :(得分:1)
如果Shoe抛出,那么Shoe没有构造,因此没有任何scoped_ptr可以真正做到。没有? scoped_ptr x在堆栈上,将在范围退出时清理。