1
#include <iostream>

using namespace std;

class Test {
public:
    
    Test(string value){
        cout<<"Ctor "<<value<<endl;
        _val=value;
    }
    Test( Test&& mv): _val(mv._val)
    {
        mv._val=string();
        cout<<"Mv constructor"<<endl;  
    }
    
    string& get()
    {
      return this->_val;
    }
private:
    string _val;
};

void print(Test&& t)
{
    cout<<"Stampa val is "<<t.get()<<endl;
}

int main()
{
    Test a{"ciao"};
    print(move(a));
    cout<<"Val of a is "<<a.get()<<endl;
    print(Test("test"));
    

    return 0;
}

其输出是(将行号添加到标准输出):

Ctor ciao
Stampa val is ciao
Val of a is ciao
Ctor test
Stampa val is test

为什么在 main 的第 2 行没有调用 mv 语义?我可能会在第四行理解有一个优化,所以只调用了构造函数,但是我无法解释第一步。有任何想法吗?

4

2 回答 2

3

std::move只是将参数转换为右值(可以稍​​后移动),它本身不执行移动操作。转换后的右值绑定到引用参数t,因此在这种情况下不会调用移动构造函数。

std::move 用于指示一个对象 t 可能被“移出”,即允许将资源从 t 有效转移到另一个对象。

特别是,std::move 产生一个 xvalue 表达式来标识它的参数 t。它完全等同于将 static_cast 转换为右值引用类型。

通常调用移动构造函数来初始化对象,它不会在引用绑定中调用(对于左值引用也是如此)。如果您更改要按值传递的参数,则将使用移动构造函数(初始化参数)。例如

void print(Test t)
{
    cout<<"Stampa val is "<<t.get()<<endl;
}

居住


顺便说一句:由于复制省略,即使更改为按值传递print(Test("test"));也不会调用移动构造函数。

BTW2:在移动构造函数中,最好val根据提供的移动操作移动初始化数据成员std::string。例如

Test( Test&& mv): _val(std::move(mv._val))
{
    cout<<"Mv constructor"<<endl;  
}
于 2021-05-20T09:53:46.163 回答
1

您的代码中只Test构造了两个对象,而不是更多。

int main()
{
    Test a{"ciao"};                          // here 
    print(move(a));
    cout<<"Val of a is "<<a.get()<<endl;
    print(Test("test"));                     // and here
}

第二个也通过Test(string)构造函数构造对象。std::move不构造对象,它只是对右值引用的强制转换。将该 rvalue 引用传递给print也不需要构造另一个Test. 如果要调用构造函数,则必须实际构造一个实例,例如:

 auto t  = Test( std::move(a) );     // calls Test(Test&&)
 auto t2 = Test( Test("move me") );  // calls Test(string) then Test(Test&&)
于 2021-05-20T10:02:11.190 回答