C++ 异常和复制构造函数:C++;
指 我运行以下代码:C++ 异常和复制构造函数:C++;,c++,C++,指 我运行以下代码: #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 co
#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.
}
我知道编译器可能已经用不必要的复制对代码进行了优化,但这里没有这样做
但是我想问的是,如何对复制构造函数进行两次调用
catch(cc)
-因为我们是按值传递的,所以在这里调用复制构造函数
但是在抛出c时,如何调用复制构造函数?有人能解释一下吗
throw c;
创建一个临时对象,并抛出该临时对象。可以通过复制/移动构造函数创建临时文件。是的,这种复制/移动可以省略
参考文献:
C++11 15.1引发异常
§3:
抛出表达式初始化一个临时对象,称为异常对象,其类型是通过从抛出操作数的静态类型中删除任何顶级cv限定符并调整类型来确定的
§5:
当抛出的对象是类对象时,即使省略了复制/移动操作,复制/移动构造函数和析构函数也应可访问(12.8)
在抛出用户定义的类型对象时复制并移动构造函数
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子句参数时,exception对象是一个左值参数
From:Alok-你能给我举个移动构造函数的例子吗?它与移动赋值运算符相同吗?请你回复EDIT
部分是@BenVoigt的问题,这些评论似乎比问题更自信,这可能是因为它们直接来自维基百科。在这里,“初始化一个临时对象”是缺少的。@GauravK:C++11除了C++03中已经存在的复制语义外,还引入了移动语义。这个问题可能是一个很好的开始。@GauravK:是的,在C++11中介绍过。通常情况下,您不应该也不能依赖计算复制/移动构造函数调用。一个好的编译器将尽可能通过RVO或NRVo应用复制省略。
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