C++ 是否应将异常链接到C++;?
我刚刚完成了一个C++程序的工作,在这个程序中我实现了我自己的异常(尽管是从std::exception派生的)。当一个异常引起连锁反应、向上传播错误并引发其他异常时,我采用的做法是在模块(读取类)的每个适当步骤连接错误消息。即,删除旧异常本身并创建新异常,但错误消息较长 这可能对我的小项目有效,但我最终对我的方法不是很满意。首先,除了最后一个例外,行号(尽管目前未应用)和文件名不会保留;事实上,这些信息在第一个例外中最为重要 我认为将异常链接在一起可以更好地处理这一问题;i、 e.旧异常在新异常的构造函数中提供。但这将如何实施?当异常超出方法的作用域时,是否会死亡,从而阻止使用异常指针?如果异常可以是任何派生类,那么如何复制和存储该异常 <>这最终导致我考虑C++中的链接异常是否是一个好主意。也许我们应该创建一个异常,然后向它添加额外的数据(就像我一直在做的那样,但可能是以更好的方式)C++ 是否应将异常链接到C++;?,c++,exception,chaining,nested-exceptions,C++,Exception,Chaining,Nested Exceptions,我刚刚完成了一个C++程序的工作,在这个程序中我实现了我自己的异常(尽管是从std::exception派生的)。当一个异常引起连锁反应、向上传播错误并引发其他异常时,我采用的做法是在模块(读取类)的每个适当步骤连接错误消息。即,删除旧异常本身并创建新异常,但错误消息较长 这可能对我的小项目有效,但我最终对我的方法不是很满意。首先,除了最后一个例外,行号(尽管目前未应用)和文件名不会保留;事实上,这些信息在第一个例外中最为重要 我认为将异常链接在一起可以更好地处理这一问题;i、 e.旧异常在新异
你对此有何反应?由另一个异常引起的异常是否应该链接在一起以保留某种“异常跟踪”——应该如何实现或者应该使用一个异常并附加额外的数据——应该如何做?另一个想法是将相关数据添加到异常对象中,然后使用一个简单的
抛出代码>语句重新抛出它。我认为在这种情况下,堆栈信息会被保留,因此您仍然知道异常的原始来源,但是测试将是一个好主意
我敢打赌,因为任何堆栈信息是否可用都是由实现定义的,所以在抛出一个裸之后,实现是否以任何方式保留堆栈信息的差异将更大代码>语句。如果希望数据比接收它的catch
块的寿命长,除了通过throw重试之外,还需要将数据从异常对象复制到链中代码>。(例如,如果该catch
块通过throw obj;
退出,则其包括)
例如,可以通过将要保存的数据放在堆上,并对异常中的私有数据实现交换
(在C++0x中移动
)
当然,在异常情况下使用堆时需要小心……但是,在大多数现代操作系统中,内存过度使用完全阻止了new
抛出,不管是好是坏。良好的内存余量和在完全崩溃时从链中删除异常应该可以保证安全
struct exception_data { // abstract base class; may contain anything
virtual ~exception_data() {}
};
struct chained_exception : std::exception {
chained_exception( std::string const &s, exception_data *d = NULL )
: data(d), descr(s) {
try {
link = new chained_exception;
throw;
} catch ( chained_exception &prev ) {
swap( *link, prev );
} // catch std::bad_alloc somehow...
}
friend void swap( chained_exception &lhs, chained_exception &rhs ) {
std::swap( lhs.link, rhs.link );
std::swap( lhs.data, rhs.data );
swap( lhs.descr, rhs.descr );
}
virtual char const *what() const throw() { return descr.c_str(); }
virtual ~chained_exception() throw() {
if ( link && link->link ) delete link; // do not delete terminator
delete data;
}
chained_exception *link; // always on heap
exception_data *data; // always on heap
std::string descr; // keeps data on heap
private:
chained_exception() : link(), data() {}
friend int main();
};
void f() {
try {
throw chained_exception( "humbug!" );
} catch ( std::exception & ) {
try {
throw chained_exception( "bah" );
} catch ( chained_exception &e ) {
chained_exception *ep = &e;
for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
std::cerr << ep->what() << std::endl;
}
}
}
try {
throw chained_exception( "meh!" );
} catch ( chained_exception &e ) {
for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
std::cerr << ep->what() << std::endl;
}
}
}
int main() try {
throw chained_exception(); // create dummy end-of-chain
} catch( chained_exception & ) {
// body of main goes here
f();
}
您可能需要查看以下内容:
这与MS在C#中所采用的方法有些不同,但似乎符合您的要求。由于提出了这个问题,C++11对标准做了一些值得注意的更改。
在关于异常的讨论中,我经常忽略这一点,但是下面的方法,嵌套异常,却起到了作用:
使用及
它在StackOverflow中进行了描述,并且介绍了如何在代码中获得异常的回溯,而无需调试器或繁琐的日志记录,只需编写一个适当的异常处理程序,它将重新显示嵌套的异常
由于可以对任何派生的异常类执行此操作,因此可以向此类回溯添加大量信息!
您还可以查看my,其中回溯看起来像这样:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
如果适用的话,这是很优雅的,但是异常的类型不能改变。正如Potatoswatter已经提到的,异常的类型不能改变,而且我发现这很麻烦,因为错误的解释在堆栈上越深入就越困难。例如,如果在访问具有错误索引的内部向量的方法中抛出IndexOutOfBoundsException,则在调用用户启动的操作的top方法中捕获IndexOutOfBoundsException没有多大意义。我在这里看到的唯一可能的方法是,要么将其链接起来,要么将其完全删除,作为替换例外。@gablin-是的,这是有道理的,我同意。不幸的是,如果您抛出一个新异常,我认为没有任何好的方法来保存有关原始异常的堆栈信息。所以你可以选择。我认为::boost::exception
是在异常中记录信息的好方法,即使您抛出了一个新的异常。它将允许你记录原始内容,我认为这通常是一个好主意。@kbrimington:的确,这个问题触及了这个问题的核心;i、 e.例外链接(或“内部例外”);我的问题只是对此进行了进一步的探讨,并询问是否应该从一开始就做出这样的承诺,还是坚持“你应该只抛出一种方法”。忘了感谢你的链接,但评论无法再编辑^^问题的答案是使用C++ 11代码> STD::NeStdEdExpAs/Cuth>类,显然C++标准库的作者相信,链异常是一件好事。我听说过Boost,但从来没有使用过它。我会检查你张贴的链接,看看这是否符合我正在寻找的答案。谢谢。@gablin-它基本上是一种结构良好的方法,允许将数据添加到catch
块中的异常中。这意味着您抛出的所有异常都必须派生自::boost::exception
,但如果是,则向异常添加信息并使用抛出重新抛出代码>当它向上传播时
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"