基本上我想在C ++中模拟.NET Exception.InnerException。我想从底层捕获异常并用另一个异常包装它并再次抛出到上层。这里的问题是我不知道如何将catched异常包装在另一个异常中。
struct base_exception : public std::exception
{
std::exception& InnerException;
base_exception() : InnerException(???) { } // <---- what to initialize with
base_exception(std::exception& innerException) : InnerException(innerException) { }
};
struct func1_exception : public base_exception
{
const char* what() const throw()
{
return "func1 exception";
}
};
struct func2_exception : public base_exception
{
const char* what() const throw()
{
return "func2 exception";
}
};
void func2()
{
throw func2_exception();
}
void func1()
{
try
{
func2();
}
catch(std::exception& e)
{
throw func2_exception(e); // <--- is this correct? will the temporary object will be alive?
}
}
int main(void)
{
try
{
func1();
}
catch(base_exception& e)
{
std::cout << "Got exception" << std::endl;
std::cout << e.what();
std::cout << "InnerException" << std::endl;
std::cout << e.InnerException.what(); // <---- how to make sure it has inner exception ?
}
}
在上面的代码清单中,我不确定如何在没有内部异常时初始化“InnerException”成员。此外,我不确定即使在func2抛出之后,从func1抛出的临时对象是否仍然存在?
答案 0 :(得分:3)
您还应该查看boost exception以了解包装的替代解决方案。
答案 1 :(得分:1)
另外我不确定是否 抛出的临时对象 func1即使在func2之后也会存活 扔?
没有。除非您使用throw;
重新抛出异常。如果您只允许一些(有限的)异常类型集,则可以实现此目的。
答案 2 :(得分:0)
//inversion of the problem :)
struct base_exception : public std::exception
{
std::list<base_exception*> snowball;
base_exception() { }
void add(base_exception* e) { snowball.push_back(e); }
};
void func2()
{
func2_exception e;
e.add(new func2_exception());
throw e;
}
void func1()
{
try
{
func2();
}
catch(base_exception& e)
{
e.add(new func1_exception());
throw e;
}
}
int main(void)
{
try
{
func1();
}
catch(base_exception& e)
{
std::cout << "Got exception" << std::endl;
//print info in the direct order of exceptions occurence
foreach(base_exception* exception, e.snowball)
{
std::cout << exception->what();
std::cout << "next exception was:" << std::endl;
}
}
}
... hmmmm
答案 3 :(得分:0)
内部异常的一个问题是在保持多态行为的同时再次抛出它的可能性。
通过实际管理异常生命周期并提供多态副本,可以(稍微)缓解这种情况。
// Base class
class exception: virtual public std::exception, private boost::noncopyable
{
public:
virtual exception* clone() const = 0;
virtual void rethrow() const = 0; // throw most Derived copy
};
// ExceptionPointer
class ExceptionPointer: virtual public std::exception
{
public:
typedef std::unique_ptr<exception> pointer;
ExceptionPointer(): mPointer() {}
ExceptionPointer(exception* p): mPointer(p) {}
ExceptionPointer(pointer p): mPointer(p) {}
exception* get() const { return mPointer.get(); }
void throwInner() const { if (mPointer.get()) mPointer->rethrow(); }
virtual char* what() const { return mPointer.get() ? mPointer->what() : 0; }
private:
pointer mPointer;
};
如何使用?
try
{
// some code
}
catch(exception& e)
{
throw ExceptionPointer(e.clone());
}
// later on
try
{
}
catch(ExceptionPointer& e)
{
e.throwInner();
}
答案 4 :(得分:0)
正如其他人所说,boost :: exception是一个不错的选择。但是,与使用公共基类方法的所有选项一样,它们依赖于从该基类派生的所有抛出异常。如果您的中间捕获处理程序需要向第三方库中的异常添加信息,则它将无法工作。
一个可能足够的选项就是拥有这样的中间捕获处理程序:
catch (std::exception& ex)
{
std::string msg = ex.what();
msg.append(" - my extra info");
ex = std::exception(msg.c_str()); // slicing assignment
throw; // re-throws 'ex', preserving it's original type
}
这仅适用于std :: exception的实现,它提供了一个带字符串参数的构造函数(例如VC ++)。带字符串的std :: exception构造函数是非标准扩展名。
答案 5 :(得分:0)
自C ++ 11起,您有了新的选择:
您可以使用std::exception_ptr。
然后保留异常,直到最后一个exception_ptr 异常被破坏。
struct base_exception : public std::exception
{
std::exception_ptr InnerException;
base_exception() {}
base_exception(std::exception& innerException)
: InnerException(std::make_exception_ptr(innerException))
{}
};