2015-11-02 156 views
7

我有这样的例子:为什么不调用std :: string移动构造函数?

#include <string> 
#include <iostream> 

class Test { 
private: 
    std::string str; 
public: 
    Test(std::string &&str_) : 
     str(str_) 
    {} 

    const std::string &GetStr() 
    { 
     return str; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    std::string there("1234567890"); 
    std::cout << "1. there: " << there << '\n'; 

    Test t1(std::move(there)); 

    std::cout << "2. there: " << there << '\n'; 
    std::cout << "3. there: " << t1.GetStr() << '\n'; 
} 

它使输出

$ ./a.out 
1. there: 1234567890 
2. there: 1234567890 
3. there: 1234567890 

这是在Linux上使用gcc 5.1.1。虽然移动后there字符串将保持有效但不确定的状态,但如果调用std :: string移动构造函数,此实现似乎会移动(而不是复制)该字符串。

如果我更换initalizer str(str_)str(std::move(str_))我得到这样的输出:

$ ./a.out 
1. there: 1234567890 
2. there: 
3. there: 1234567890 

此建议的std :: string移动构造函数现在使用的,但为什么在我的第一个例子是不是std::string(std::string &&)调用?

回答

6

你应该做

public: 
    Test(std::string &&str_) : 
     str(std::move(str_)) 
    {} 

str_确实有一个名字,是一个命名对象,所以它不会被传递给任何函数作为右值引用。

由标准委员会制定的设计选择防止它被视为右值,因此您不能无意中修改它。特别是:str_ do的类型是参考string的左值,但str_不被视为右值,因为它是一个命名对象。

您必须通过添加致电std::move来明确您的意图。这样做你说你想str_是一个右值,你知道这个选择的所有后果。

3

因为左值参考总是赢的!这就是为什么你需要明确指定std::move

它被允许通过类型以形成引用的引用在模板或类型定义 操作,在这种情况下,参考 塌陷规则:右值参照右值参考塌陷 到右值参考,其他所有组合形成左值参考:

typedef int& lref; 
typedef int&& rref; 
int n; 
lref& r1 = n; // type of r1 is int& 
lref&& r2 = n; // type of r2 is int& 
rref& r3 = n; // type of r3 is int& 
rref&& r4 = 1; // type of r4 is int&& 

here服用。

相关问题