为什么没有调用std :: string移动构造函数?

bin*_*y01 7 c++

我有这个例子:

#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';
}
Run Code Online (Sandbox Code Playgroud)

它给出了输出

$ ./a.out
1. there: 1234567890
2. there: 1234567890
3. there: 1234567890
Run Code Online (Sandbox Code Playgroud)

这是在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 
Run Code Online (Sandbox Code Playgroud)

这表明现在使用了std :: string移动构造函数,但为什么std::string(std::string &&)在我的第一个例子中没有调用它?

Pao*_*o M 6

你应该做

public:
    Test(std::string &&str_) :
        str(std::move(str_))
    {}
Run Code Online (Sandbox Code Playgroud)

str_ 有一个名称,是一个命名对象,所以它不会作为rvalue-reference传递给任何函数.

标准委员会做出的设计选择可以防止将其视为右值,因此您无法无意中对其进行修改.特别是:str_do 的类型是左值引用string,但str_不被视为右值,因为它是一个命名对象.

您必须通过添加呼叫来明确您的意图std::move.这样做,你声明你想str_成为一个右值,你知道这个选择的所有后果.