11

参考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如何调用复制构造函数呢?有人可以解释吗?

4

3 回答 3

14
throw c;     

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


参考:
C++11 15.1 抛出异常

§3:

throw-expression 初始化一个临时对象,称为 exception object,其类型通过从 throw 操作数的静态类型中删除任何顶级 cv 限定符并调整类型来确定........ .

§5:

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

于 2013-05-08T05:03:14.877 回答
0

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

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

int main()
{
    throw demo{};
    return 0;
}
  • 在 throw 表达式时,总是需要创建异常对象的副本,因为原始对象在堆栈展开过程中超出范围。
  • 在初始化期间,我们可能会期望复制省略(参见this)——省略复制或移动构造函数(对象直接构造到目标对象的存储中)。
  • 但是,即使可能会或可能不会应用复制省略,您也应该提供正确的复制构造函数和/或移动构造函数,这是 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 子句参数时,异常对象是一个左值参数。

来自:C++ 中异常处理的 7 个最佳实践

于 2019-11-09T08:01:32.043 回答
0

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

如果您想这样做,C++ 异常必须是可复制/移动可构造的,throw ex;因为幕后发生的事情是 C++ ABI 将在某处分配一个异常对象(通过 __cxa_allocate_exception)并复制/移动您的异常对象,无论它是在堆上还是在堆栈上,在它实际开始堆栈展开过程之前。

参考https://blog.the-pans.com/cpp-exception-2/

于 2021-11-29T18:42:27.847 回答