为什么异常的析构函数被调用两次
Why is the destructor of an exception called twice?
我有以下程序:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess)
{
cout << "MyError::MyError()n";
}
MyError::~MyError(void)
{
cout << "MyError::~MyErrorn";
}
int main(void)
{
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbyen";
return 0;
}
打印以下内容:
MyError::MyError()
MyError::~MyError
hi
MyError::~MyError
goodbye
为什么异常(~MyError())的析构函数被调用两次?
我假定throw创建了一个新对象,但是我不明白为什么要调用类析构函数
如果您检测异常的copy或move构造函数,您会发现它在处理程序之前被调用一次。有一个临时的异常对象,抛出的表达式被复制/移动到其中,处理程序中的引用将绑定到这个异常对象。c++ 14 15.1/3 +
所以你的代码的执行结果看起来像这样(伪c++):// throw MyError("hi"); expands to:
auto tmp1 = MyError("hi");
auto exceptionObject = std::move(tmp1);
tmp1.~MyError();
goto catch;
// catch expands to:
MyError& exc = exceptionObject;
cout << exc.what() << endl;
// } of catch handler expands to:
exceptionObject.~MyError();
// normal code follows:
cout << "goodbyen";
因为您的编译器未能删除由异常处理机制管理的从临时对象到异常对象的副本。
从概念上讲,MyError("hi")
创建了一个临时对象,它将在语句结束时被销毁(在异常被处理之前)。throw
将抛出的值复制到其他地方,它将一直存在,直到异常被处理。如果抛出值是临时的,那么一个体面的编译器应该省略该副本并直接初始化抛出值;显然,你的编译器没有这样做。
我的编译器(GCC 4.8.1)做得更好:
MyError::MyError()
hi
MyError::~MyError
goodbye
您的异常正在被复制。如果使用了复制器,可以看到:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(MyError const &e) : runtime_error("copy") { std::cout << "Copy MyError"; }
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess) {
cout << "MyError::MyError()n";
}
MyError::~MyError(void) {
cout << "MyError::~MyErrorn";
}
int main(void) {
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbyen";
return 0;
}
结果:MyError::MyError()
Copy MyError
MyError::~MyError
copy.what()
MyError::~MyError
goodbye
相关文章:
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- C++析构函数调用两次,堆栈分配的复合对象
- Qt插槽调用了两次
- 对于优化级别为 0 的 std::vector,析构函数被调用两次
- 为什么转换运算符调用复制构造函数两次,而等效函数只调用它一次
- 调用一个小函数两次(例如在if条件和主体中)比将结果存储在局部变量中更可取
- 为什么这个自定义分配器的析构函数在 GCC/MSVS 的 stdlib 中被调用两次
- 插槽调用了两次qt
- 调用某个回调函数两次会导致分段错误:Nan
- 基于 MFC 对话框的应用程序无法调用对话框两次
- 重载运算符 new(),为什么构造函数被调用两次?
- 当 reset() 被unique_ptr调用两次时会发生什么?
- 为什么在C 中超载邮政增量运算符两次调用构造函数
- 现代C++编译器是否能够避免在某些条件下两次调用常量函数
- 如果我对async_read进行两次调用,那么只有在处理完第一次调用之后,才会处理第二次调用,这是否安全
- 如何正确地将对象添加到向量,而无需两次调用析构函数
- boost::asio vs. libpcap:避免两次调用关闭
- 为什么 DNSServiceProcessResult 两次调用我的回调
- 在资源管理器左窗格上两次调用Windows 7外壳扩展dll Initialize方法
- 通过连续两次调用boost::asio::read来检索正确的数据