与构造函数参数相关的异常安全的习语

Idiom for exception safety relating to constructor parameters

本文关键字:异常 习语 安全 构造函数 参数      更新时间:2023-10-16

我一直在看我正在处理的一些代码,我们有这样的等价物:

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++习语可以解决此问题,例如,制作调用负责清理参数的构造函数的代码?我见过的大多数代码似乎都没有这样做......

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

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

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

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

如果要保留由 x 管理的A对象以防发生异常,则可以改为将AutoPtr<A>&传递给 B 的构造函数。

。它应该负责删除参数本身(或者应该删除?

不,不应该。

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));

但目前缺少作为监督。

像这样的东西,可能是:

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

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