我发现有三种方法可以捕获异常,有什么区别?
1)按值抓住;
2)通过引用捕获;
3)用指针抓住;
我只知道按值捕获将调用该对象的两个副本,通过引用捕获将调用一个。那么指针捕获怎么样?什么时候用指针捕捉?除了抛出一个对象,我可以抛出一个像这样的对象的指针吗?
class A {}
void f() {
A *p = new A();
throw p;
}
答案 0 :(得分:76)
建议的方法是按值抛出并按引用引用。
您的示例代码会抛出一个指针,这是一个坏主意,因为您必须在catch站点管理内存。
如果您确实觉得应该抛出指针,请使用智能指针,例如shared_ptr
。
无论如何,Herb Sutter和Alexei Alexandrescu在我的C ++编码标准书中解释得非常好。
请参阅C++ Coding Standards: Throw by Value, Catch by Reference。
答案 1 :(得分:15)
Catch遵循正常的赋值兼容性规则,也就是说,如果抛出一个值,则可以将其作为值或引用捕获,而不是作为指针;如果你抛出一个指针,你只能把它作为指针(或对指针的引用......)来捕获。
但抛出指针并没有多大意义,它只会导致内存管理问题。因此,您应该按照规则按值抛出,按引用捕获,如Gregory所解释的那样。
答案 2 :(得分:4)
Microsoft的MFC使用catch by pointer,但我认为这是为了在try和catch正确实现之前与编译器兼容;最初他们使用TRY和CATCH宏来模拟它。每个异常都派生自CException,它具有确定是否需要删除对象的方法。
我不建议任何现代的异常设计。通过引用抓住是要走的路。
答案 3 :(得分:2)
虽然可以抛出任何类型的任何对象,但这样做几乎没有(如果有的话)。动态分配主要用于对象需要生命周期不适合自动分配的情况 - 即您希望其生命周期独立于正常的程序范围。
然而,在异常对象的情况下,这并没有多大意义。异常对象通常仅在异常处理程序中使用,并且当您退出该异常的(最后一个)处理程序时,您显然希望它被销毁。
还有一个事实是,您通常希望保持异常处理代码相当简单。例如,如果你试图报告免费存储/堆已经耗尽或损坏,那么试图将你的异常对象分配给耗尽/损坏的免费存储/堆通常不会很好地工作......
答案 4 :(得分:1)
通过指针捕获/抛出异常并不是一个好的方案。 C ++语义允许它,但它并不是非常有用,因为大多数时候你会抛出一个临时异常或字符串对象。
但是,有些库(Boost.Graph这样做,我相信)使用throw将一个返回值从一个深度递归的函数传递给调用者;在这种情况下,返回值可能是指针,因此抛出指针是有意义的。