C++ 如果抛出的异常总是异常对象的副本,为什么不是';是否正在调用此副本构造函数?

C++ 如果抛出的异常总是异常对象的副本,为什么不是';是否正在调用此副本构造函数?,c++,C++,斯科特·迈尔斯说: C++指定始终复制作为异常抛出的对象,并由对象的复制构造函数执行复制 但在我的代码中: struct test { test() { cout << "constructor is called" << endl; } test(const test&) { cout << "copy constructor is called" << endl; } ~test() { cout <<

斯科特·迈尔斯说:

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; }
}
struct测试
{

test(){coutMeyers正确地指出,从语义上来说,复制是正确的:

[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]:
当满足某些条件时,允许实现忽略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。在这种情况下,实现将忽略的复制/移动操作的源和目标视为两个不同的引用同一对象的时间间隔,并且该对象的销毁发生在两个对象在未经优化的情况下销毁的较晚时间。在以下情况下,允许省略复制/移动操作,称为“复制省略”(copy elision)(可以组合以消除多个副本):

  • [……]
  • 当未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv类型的类对象时,可以通过将临时对象直接构造到省略的复制/移动目标中来省略复制/移动操作
  • [……]

问题是“哪一个是错的:Meyers还是我的编译器?”不要因为不理解而关闭问题。对于12.8/31,我们实际上是在下一种情况下,“当一个临时类对象未绑定到引用(12.2)时”将复制/移动到具有相同cv不合格类型的类对象,可以通过将临时对象直接构造到省略的复制/移动的目标中来省略复制/移动操作。“
test()
是临时的,以未指定的方式分配的异常对象是它要复制/移动到的对象,它恰好也是临时的。在您突出显示的情况下,我们没有这样做,因为操作数
test()
不是对象的名称。@SteveJessop:True。另外,我认为关于作用域的条件失败是因为“函数调用间接寻址”(由我编造的术语)。@SteveJessop:最后一个大小写是否因为accept by ref而不相关?您突出显示的位是允许在
void fun(){test foo;throw foo;}的情况下省略副本所以
foo
的作用域只是函数
fun()
,它不包含最里面的try块。我不知道为什么它禁止对
void fun(){try{test foo;throw foo;}catch(std::bad_alloc&}
void fun(test foo){throw foo;}进行复制省略
,但是,我不太明白为什么在这种情况下会有人想依赖副本的副作用。嗯,我不会想太多。这个答案是正确的:“够了”。)