【问题标题】:Why wasn't std::string move constructor called?为什么不调用 std::string 移动构造函数?
【发布时间】:2023-03-16 23:04:01
【问题描述】:

我有这个例子:

#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 移动构造函数,此实现似乎会移动(而不是复制)字符串。

如果我用str(std::move(str_)) 替换初始化器str(str_),我会得到这个输出:

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

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

【问题讨论】:

    标签: c++


    【解决方案1】:

    你应该这样做

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

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

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

    您必须通过添加对std::move 的调用来明确您的意图。这样做表示您希望 str_ 成为右值,并且您知道此选择的所有后果。

    【讨论】:

      【解决方案2】:

      因为左值引用总是获胜!这就是为什么您需要明确指定std::move

      允许通过类型形成对引用的引用 模板或 typedef 中的操作,在这种情况下引用 折叠规则适用:对右值引用的右值引用折叠 对于右值引用,所有其他组合形成左值引用:

      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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 2019-12-09
        相关资源
        最近更新 更多