异常和复制构造函数:C ++

时间:2013-05-08 04:58:24

标签: c++

参考http://en.wikipedia.org/wiki/Copy_elision

我在代码下面运行:

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "Hello World!\n"; }
};

void f() {
  C c;
  throw c; // copying the named object c into the exception object.
}          // It is unclear whether this copy may be elided.

int main() {
  try {
    f();
  }
  catch(C c) {  // copying the exception object into the temporary in the exception declaration.
  }             // It is also unclear whether this copy may be elided.
}

我得到的输出:

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ make clean
rm -f Trial.exe Trial.o

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ make
g++ -Wall Trial.cpp -o Trial

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ ./Trial
Hello World!
Hello World!

据我所知,编译器可能已经使用不必要的复制优化了代码,但这并没有在这里进行。

但我想问的是,two calls to the copy constructor是如何制作的?

catch(C c) - 因为我们正在传递值,所以这里调用了复制构造函数。

但是在throw c如何调用复制构造函数?有人可以解释一下吗?

2 个答案:

答案 0 :(得分:12)

throw c;     

创建一个临时对象,抛出此临时对象。临时的创建可能是通过复制/移动构造函数。是的,这个复制/移动可以省略。


<强>参考文献:
C ++ 11 15.1抛出异常

§3:

  

throw-expression初始化一个临时对象,称为异常对象,其类型是通过从throw和adjust的操作数的静态类型中删除任何顶级cv限定符来确定的。类型.........

§5:

  

当抛出的对象是类对象时,即使复制/移动操作被省略,也应该可以访问复制/移动构造函数和析构函数(12.8)。

答案 1 :(得分:0)

在复制并移动构造函数时抛出用户定义的类型对象

struct demo
{
    demo() = default;
    demo(demo &&) = delete;
    demo(const demo &) = delete;
};

int main()
{
    throw demo{};
    return 0;
}
  • 在引发表达式时,总是需要在堆栈展开过程中原始对象超出范围时创建异常对象的副本。
  • 在初始化期间,我们可能期望复制省略(参见此内容)–省略复制或移动构造方法(将直接构造的对象存储到目标对象的存储中)。
  • 但是,即使可以使用复制省略或不使用复制省略,您也应提供适当的复制构造函数和/或移动构造函数,这是C ++标准规定的(请参见15.1)。请参阅下面的编译错误以供参考。
error: call to deleted constructor of 'demo'
    throw demo{};
          ^~~~~~
note: 'demo' has been explicitly marked deleted here
    demo(demo &&) = delete;
    ^
1 error generated.
compiler exit status 1
  • 如果我们按值捕获异常,则我们也可能期望复制省略(允许编译器这样做,但这不是强制性的)。初始化catch子句参数时,异常对象是一个左值参数。

发件人:7 best practices for exception handling in C++