2

假设我有一些类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

4 回答 4

3

智能指针有一个reset方法:

boost::shared_ptr<Foo> f;
//...
f.reset(new Foo(...));

这解决了你的“失败#3”,让你做你想做的事。

于 2013-05-31T15:29:41.987 回答
2

保持f基于堆栈的正确方法是尊重范围:

try {
  Foo f(...);
  ... entire code using f ...
}
catch(...) {}
于 2013-05-31T15:33:58.733 回答
2

一种解决方案可能是使用 boost::optional(或 C++14 的std::optional):

boost::optional<Foo> f;
try { f = Foo(...); }
于 2013-05-31T15:51:01.820 回答
1

如果您使用正确的 .reset() 方法,您的智能指针 case 和 like 可以正常工作。

但是,该问题不适合正常用例,要么是该类设计错误,要么您使用不正确。正常使用应该像 case#1 一样在块内使用 F 。或者没有 try 块并将 catch 留给上游。

编辑:针对最近的评论和原始问题,我坚持不欢迎在最终用户代码中尝试块的立场。对于我使用某些 throw 策略处理第三方组件的情况,如果它不符合我的需要,我会编写包装器,将异常转换为错误返回或错误代码抛出异常。并使用该扩展组件。

在这种情况下,用户会被抛出 ctor 所困扰。所以它可以通过将ctor包装在一个函数中来处理:

Foo* new_foo( ARGS )
{
    try{
       return new Foo( ARGS );
    }
    catch( const FooException& )
    {
         return NULL;
    }
}

然后让客户端代码没有 try 块,更重要的是,没有赋值。只会const unique_ptr<Foo> p(new_foo(...))做。

于 2013-05-31T15:33:16.467 回答