从构造函数捕获Exception,而不将对象隐藏在try块中

Catch Exception from constructor without hiding the object in the try block

本文关键字:对象 隐藏 块中 try 构造函数 Exception      更新时间:2023-10-16

我有一个类,它的构造函数可能抛出异常。

class A {
    A() { /* throw exception under certain circumstances */ }
};

我想在客户端为堆栈分配的实例捕获此异常。但是我发现自己不得不扩展try块,至少到实例必须是活的为止。

try {
    A a;
    do_something(a);
} catch {
    // ...
}

现在,当try块太大而无法追踪异常的来源时,这显然成为一个问题:

try {
    A a1;
    A a2;
    do_something(a1, a2);
} catch {
    // Who caused the exception?
}

我该怎么做才能避免这种情况?

:

似乎我没有很好地解释这个问题:出于显而易见的原因,我想让try块跨越尽可能少的代码(也就是说,只有构造)。

但是这会产生一个问题,我不能在之后使用对象,因为它们已经移出了作用域。

try {
    A a1;
} catch {
    // handle a1 constructor exception
}
try {
    A a2;
} catch {
    // handle a2 constructor exception
}
// not possible
do_something(a1, a2);

不需要更改A的解决方案是使用嵌套的try/catch块:

try {
    A a1;
    try {
        A a2;
        do_something(a1, a2);
    }
    catch {
      // a2 (or do_something) threw
    }
} catch {
    // a1 threw
}

使用堆构造对象而不是堆栈构造对象,这样您就可以测试哪些对象已经成功构造,例如:

// or std::unique_ptr in C++11, or boost::unique_ptr ...
std::auto_ptr<A> a1_ptr;
std::auto_ptr<A> a2_ptr;
A *a1 = NULL;
A *a2 = NULL;
try
{
    a1 = new A;
    a1_ptr.reset(a1);
}
catch (...)
{
}
try
{
    a2 = new A;
    a2_ptr.reset(a2);
}
catch (...)
{
}
if( (a1) && (a2) )
    do_something(*a1, *a2);

或者(仅当A是可复制构造的):

boost::optional<A> a1;
boost::optional<A> a2;
try
{
    a1 = boost::in_place<A>();
    a2 = boost::in_place<A>();
}
catch (...)
{
    //...
}
if( (a1) && (a2) )
    do_something(*a1, *a2);

另一种在某些情况下可能很方便的方法:

class ExceptionTranslatedA : public A {
public:
    template<typename Exc>
    ExceptionTranslatedA(Exc exc)
    try : A() {}
    catch (unhelpful_generic_exception) {
        throw exc;
    }
};

如果抛出一个不同的异常是你想在原来的try-catch块中做的所有事情,这是特别有用的,因为你可以完全摆脱它。它也比为控制流引入布尔变量(即使它们隐藏在boost::optional中)感觉更优雅。