假设我有一些类Foo
,它没有在非默认构造函数中定义默认构造函数和throws
。初始化类型的新对象时,我想捕获任何异常并返回,否则继续使用该对象。我注意到,如果可能的话,很难在堆栈上初始化这个对象或者通过使用共享指针,因为我试图避免管理内存。
失败1
Foo f; // doesn't work, no default constructor
try { f = Foo(...); }
失败2
try {
Foo f(...)
}
catch(...) {}
// doesn't work, f is inaccessible
失败3
boost::shared_ptr<Foo> pf;
try { pf = new Foo(...); } // no assignment operator
我必须......
Foo *f;
try { f = new Foo(...) } // okay, let's just manage the memory
有办法吗?
修改
好的,所以这很有效,尽管不是最干净的。有更“标准”的方式吗?
boost::shared_ptr<Foo> pf;
try { pf = boost::shared_ptr<Foo>(new Foo(...)); }
答案 0 :(得分:3)
智能指针有reset
方法:
boost::shared_ptr<Foo> f;
//...
f.reset(new Foo(...));
这解决了你的“失败#3”并允许你做你想做的事。
答案 1 :(得分:2)
保持f
基于堆栈的正确方法是尊重范围:
try {
Foo f(...);
... entire code using f ...
}
catch(...) {}
答案 2 :(得分:2)
一种解决方案可能是使用boost::optional
(或C ++ 14的std::optional
):
boost::optional<Foo> f;
try { f = Foo(...); }
答案 3 :(得分:1)
如果你使用正确的.reset()方法,你的智能指针盒和喜欢工作正常。
然而,该问题不适合正常使用情况,要么是错误设计了类,要么是错误地使用了它。正常使用应该像块#1一样在块内进行。或者不尝试阻止并将捕获留给上游。
编辑: 针对最近的评论以及原始问题,我保持我的立场,即不欢迎在最终用户代码中尝试块。对于我使用某种抛出策略处理第三方组件的情况,如果它不符合我的需要,我会编写包装器,将异常转换为错误返回或错误代码抛出异常。并使用该扩展组件。
对于这种情况,用户会因投掷ctor而烦恼。所以它将通过将ctor包装在一个函数中来处理:
Foo* new_foo( ARGS )
{
try{
return new Foo( ARGS );
}
catch( const FooException& )
{
return NULL;
}
}
然后让客户端代码没有try块,更重要的是,没有任务。只需const unique_ptr<Foo> p(new_foo(...))
即可。