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

Exception and Copy Constructor : C++

本文关键字:c++ 构造函数 复制 异常      更新时间:2023-10-16

参考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是如何复制构造函数被调用?有人能解释一下吗?

throw c;     

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


引用:
c++ 11 15.1抛出异常

§3:

throw表达式初始化一个临时对象,称为异常对象,该对象的类型通过从throw操作数的静态类型中删除任何顶级cvs限定符并调整类型.........

来确定。

§5:

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

Copy &当抛出用户定义类型对象

时移动构造函数
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子句形参时,异常对象是左值实参。

选自:c++中异常处理的7个最佳实践

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

c++异常必须是复制/移动可构造的,如果你想做throw ex;作为场景背后发生的事情是,c++ ABI将分配一个异常对象(通过__cxa_allocate_exception) 某处和复制/移动你的异常对象,无论是在堆或堆栈上,在它实际开始堆栈展开过程之前。

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