我有一个类,其构造函数可能抛出异常。
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);
答案 0 :(得分:6)
不需要更改A
的解决方案是使用嵌套的try / catch块:
try {
A a1;
try {
A a2;
do_something(a1, a2);
}
catch {
// a2 (or do_something) threw
}
} catch {
// a1 threw
}
如果可能的话,可能最好避免这样做。
答案 1 :(得分:3)
使用堆构造的对象而不是堆栈构造的对象,以便您可以测试哪些对象已成功构建,例如:
// 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);
答案 2 :(得分:0)
在某些情况下可能很方便的另一种方法:
class ExceptionTranslatedA : public A {
public:
template<typename Exc>
ExceptionTranslatedA(Exc exc)
try : A() {}
catch (unhelpful_generic_exception) {
throw exc;
}
};
如果您想在原始try-catch块中执行所有操作,则此功能特别有用,因为您可以完全摆脱它。它也比为控制流引入布尔变量感觉更优雅(即使它们隐藏在boost::optional
s中)。