C++ 为什么抛出局部变量调用移动构造函数?

C++ 为什么抛出局部变量调用移动构造函数?,c++,exception,c++11,move-semantics,C++,Exception,C++11,Move Semantics,最近,我与右值“玩”来了解它们的行为。大多数结果并没有让我吃惊,但后来我看到,如果我抛出一个局部变量,就会调用move构造函数 在此之前,我认为移动语义规则的目的是确保只有在编译器能够检测到不再使用对象(如在临时对象中)或用户承诺不使用对象(如在std::move中)时,对象才会移动(并变得无效) 但是,在下面的代码中,这些条件都不成立,并且我的变量仍在移动(至少在g++4.7.3上是这样) 为什么呢 #include <iostream> #include <string&g

最近,我与右值“玩”来了解它们的行为。大多数结果并没有让我吃惊,但后来我看到,如果我抛出一个局部变量,就会调用move构造函数

在此之前,我认为移动语义规则的目的是确保只有在编译器能够检测到不再使用对象(如在临时对象中)或用户承诺不使用对象(如在std::move中)时,对象才会移动(并变得无效)

但是,在下面的代码中,这些条件都不成立,并且我的变量仍在移动(至少在g++4.7.3上是这样)

为什么呢

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s="blabla";
    try {
        throw s;
    }
    catch(...) {
        cout<<"Exception!\n";
    }
    cout<<s; //prints nothing
}
#包括
#包括
使用名称空间std;
int main(){
字符串s=“blabla”;
试一试{
掷骰子;
}
捕获(…){
coutC++标准说明(15.1.3):

抛出异常副本会初始化(8.5,12.8)一个临时对象,称为异常对象。临时对象是一个左值,用于初始化匹配处理程序(15.3)中命名的变量。 本段也可能与此相关(12.8.31):

当满足某些条件时,允许实现忽略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数有副作用。在这种情况下,实现将忽略的复制/移动操作的源和目标视为两个简单的不同指代同一对象的不同方式,以及对该对象的破坏 在两个对象在未经优化的情况下被销毁的较晚时间发生。在以下情况下(可以组合使用以消除多个副本),允许省略复制/移动操作(称为复制省略):

(…)

-在抛出表达式中,当操作数是一个非易失性自动对象(函数或catch子句参数除外)的名称,该对象的作用域不超出最里面的封闭try块(如果有)的结尾时,从操作数到异常对象的复制/移动操作(15.1)可以通过将自动对象直接构造到异常对象中来省略 已在Visual Studio 2012中签入,效果:

Exception!
blabla

它看起来确实像是GCC中的一个bug。

在给定的情况下,它可能是一个编译器bug,因为抛出(并从中移动)的变量随后被引用


在一般情况下,调用move on
throw
在概念上与move on
return
相同。当已知变量在给定点(
throw
return
)之后无法被引用时,最好自动调用move。

如果是这样,看起来像是gcc中的错误。@kbok:你说得对,我删除了我的答案(所以我在这里回答你的评论)。我不知怎的认为
s
是在
try
块中声明的,应该仔细阅读问题。对不起all@JonathanWakely报告-谢谢,确认为bug@JoachimIsaksson您应该添加-std=c++0x2。如果是这样,即使
抛出
不在中,编译器也不允许调用移动构造函数de>try
block?@asaelr:从更新的引文来看,要抛出的对象似乎可以复制、移动,甚至可以就地构造-与返回值相同。@asaelr是。但在这种特殊情况下,它错误地调用了move-ctor,因为该变量后来在try-block.FWIW中使用,VC++实现了小字符串优化但对于较长的字符串,输出与预期的一样。其范围确实超出了最内层的封闭try块。该字符串在此之前已声明。