如果引发的异常始终是异常对象的副本,为什么不调用此复制构造函数?
If a thrown exception is always a copy of the exception object, why isn't this copy constructor being invoked?
Scott Meyers说:
C++指定始终复制作为异常抛出的对象,并且复制由对象的复制构造函数执行。
但在我的代码中:
struct test
{
test() { cout << "constructor is called" << endl; }
test(const test&) { cout << "copy constructor is called" << endl; }
~test() { cout << "destructor is called" << endl; }
};
void fun()
{
throw test();
}
int main()
{
try {
fun();
}
catch (test& t1) { cout << "exception handler" << endl; }
}
我没有看到异常对象的复制构造函数被调用。
如果我更改catch
以按值接收异常对象,那么它就是,但根据Meyers的引用,即使通过引用接收异常对象也应该复制它。
为什么不调用复制构造函数(即使通过引用执行异常处理)
Meyers在语义上认为复制是正确的:
[C++11: 12.2/1]:
类类型的临时在各种上下文中创建:绑定对prvalue的引用(8.5.3),返回prvalue(6.6.3),创建prvalue的转换(4.1、5.2.9、5.2.11、5.4),抛出异常(15.1),输入处理程序(15.3),以及在某些初始化中(8.5)。[…]
[C++11: 15.1/4]:
抛出异常的临时副本的内存以未指定的方式分配,3.7.3.1中指出的除外。只要有一个处理程序正在为该异常执行,临时就会持续存在。
然而,聪明的编译器可以消除副本,并且允许他们这样做,而不考虑副作用。
[C++11: 12.8/31]:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使该对象的复制或移动构造函数和/或析构函数有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象在没有优化的情况下被销毁的较晚时间。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以组合以消除多个副本):
- [..]
- 当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv不合格类型的类对象,通过将临时对象直接构建到被省略的复制/移动的目标中,可以省略复制/移动操作
- [..]
由于C++11,当一个对象作为异常抛出时,复制到异常对象可能会被消除,如果复制消除的条件已经满足或将要满足,除了源是函数参数,但编译器由于某些原因没有消除它,编译器必须尝试使用move构造函数,即使对象是由左值指定的。
- C++/CLI System.AccessViolation在托管类中调用非托管函数时出现异常
- 尝试在 QT 项目中调用 Java 代码时未找到类异常
- 调用参数不是原子参数的函数是此代码引发异常的原因吗?
- 从 C# 调用 C++ DLib 会导致错误的分配异常
- 在 postOrderDelete 上调用析构函数时引发的异常
- memcpy() 在一个类中被调用以复制到另一个类变量中后会引发异常
- 为什么在析构函数中引发异常时不调用重载删除
- CPP 异常获取抛出调用方的详细信息
- 为什么要抛出引用调用复制构造函数的异常?
- 析构函数中的互斥锁C++在 Python 中调用 exit() 时会导致异常
- 调试"在抛出 ..) 实例后终止调用",当异常 _should_ 被捕获时
- 调用系统调用函数时出现异常
- 如果从在其他函数中调用的函数引发异常会发生什么情况
- C++函数中引发异常并在调用方中捕获它
- 防止线程在处理异常后在分离时调用 std::terminate()
- 如果从类成员初始值设定项引发的异常调用 std::terminate()
- 从 c# 内存不足异常调用 c++ 委托
- 析构函数的异常调用
- 加密++异常调用消息结束
- 避免对特定异常调用析构函数