使用“抛出”构造函数避免堆分配

时间:2013-05-31 15:25:55

标签: c++

假设我有一些类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(...)); }

4 个答案:

答案 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(...))即可。