与构造函数参数相关的异常安全的惯用法

时间:2012-10-10 00:19:37

标签: c++ exception-safety

我一直在研究一些我正在研究的代码,我们有相同的代码:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Detach());

其中AutoPtr是我们的auto_ptr版本,Detach()返回拥有的指针并重置自身。此外,B()取得x的所有权。

现在,我意识到如果new抛出std :: bad_alloc,这将泄漏x,所以我将代码更改为:

AutoPtr<A> x;
...
/// x gets initialized
...
B* y = new B(x.Get());
x.Detach();

但后来我意识到,如果B()'拥有'指针,并且在构造过程中发生异常,它应该注意删除参数本身(或者它应该吗?),因此x将被删除两次,一次由B(),一次由x的析构函数。

现在,是否存在解决此问题的C ++习惯用法,例如,调用构造函数的代码负责清理参数?我见过的大多数代码似乎都不这么做......

3 个答案:

答案 0 :(得分:3)

显而易见的解决方案似乎是将临时AutoPtr<A>传递给B的构造函数:

AutoPtr<B> y(new B(AutoPtr<A>(x));

(这也为从B*返回的new B()添加了资源控制。

B的构造函数只需调用x.Detach()来初始化使用A*进行初始化所需的任何内容。如果在任何时候发生异常,AutoPtr<A>将释放该对象。

如果您希望在发生异常时保留A管理的x对象,则可以将AutoPtr<A>&传递给B的构造函数。

答案 1 :(得分:3)

  

...它应该注意删除参数本身(或者它应该?)

不,它不应该。

B在构造函数完成之前不存在,如果它不存在则不应该声明对任何东西的所有权(对于某一点;如果构造函数本身做了某些事情,那么它需要是安全的孔)。

C ++习惯用法是不使用原始指针作为所有权(包括y)! B应接受AutoPtr作为参数,以便调用者可以这种方式放弃所有权。这是std::unique_ptrstd::move的目标:

std::unique_ptr<A> x;

std::unique_ptr<B> y(new B(std::move(x)));

另请注意,真的new也不应该像这样使用;而是使用make_*实用程序:

auto y = std::make_unique<B>(std::move(x));

但目前缺少这种疏忽。

答案 2 :(得分:0)

这样的事情可能是:

B* y = new B();
y->Attach(x.Detach());

B* y = new B();
(*y) = x;