c++ std::move

std::move的原理

std::move的定义:

这里,T&&是通用引用,需要注意和右值引用(比如int&&)区分。通过move定义可以看出,move并没有”移动“什么内容,只是将传入的值转换为右值,此外没有其他动作。std::move+移动构造函数或者移动赋值运算符,才能充分起到减少不必要拷贝的意义。

std::move的使用场景

在之前的项目中看到有的同事到处使用std::move,好像觉得使用了std::move就能移动资源,提升性能一样,在我看来,std::move主要使用在以下场景:

  • 使用前提:1 定义的类使用了资源并定义了移动构造函数和移动赋值运算符,2 该变量即将不再使用
  • 使用场景
RValue a, b;
    
//对a,b坐一系列操作之后,不再使用a,b,但需要保存到智能指针或者容器之中
unique_ptr<RValue> up(new RValue(std::move(a)));
vector<RValue*> vr;
vr.push_back(new RValue(std::move(b)));

//临时容器中保存的大量的元素需要复制到目标容器之中    
vector<RValue> vrs_temp;
vrs_temp.push_back(RValue());
vrs_temp.push_back(RValue());
vrs_temp.push_back(RValue());
vector<RValue> vrs(std::move(vrs_temp));
    
RValue c;
put(std::move(c));
View Code

 

  • 在没有右值引用之前,为了使用临时变量,通常定义const的左值引用,比如const string&,在有了右值引用之后,为了使用右值语义,不要把参数定义为常量左值引用,否则,传递右值时调用的时拷贝构造函数
void put(const RValue& c){
    cout<<"----------"<<endl;
    unique_ptr<RValue> up(new RValue(std::move(c)));
    cout<<"----------"<<endl;
}

RValue c;
put(std::move(c));

g++ move.cpp -std=c++11 -o move
 ./move 
----------
& RValue
----------
View Code

 

不使用左值常量引用:

void put(RValue c){
    cout<<"----------"<<endl;
    unique_ptr<RValue> up(new RValue(std::move(c)));
    cout<<"----------"<<endl;
}

RValue c;
put(std::move(c));

g++ move.cpp -std=c++11 -o move
 ./move 
&& RValue
----------
&& RValue
----------
View Code

 

这是因为,根据通用引用的定义,std::move(c)过程中,模板参数被推倒为const RValue&,因此,调用拷贝构造函数。

 

  • unique_ptr

形参为unique_ptr u2,而后实参为std::move(unique_ptr u1),这样会将原本u1的内存传递给u2,避免了传递拷贝。例如

 void fun(std::unique_ptr u2)
 {
 }
 
unique_ptr<cls> u1;
fun(std::move(u1));
View Code

 

 

总结

通过简绍右值和右值引用以及std::move和移动构造函数,总结右值引用,移动构造函数和移动赋值运算符和std::move的用法和注意事项。

 

转自:

https://zhuanlan.zhihu.com/p/94588204

posted @ 2021-05-07 17:08  Calla11  阅读(957)  评论(0)    收藏  举报