我一直在看我正在处理的一些代码,我们有这样的等价物:
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_ptr
和std::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;