前言
std::move()的原始语义,是将一个左值变为右值,它本身并不涉及到调用拷贝构造还是调用移动构造。不要有使用std::move()是为了调用移动构造函数这种错觉。比如在下面的例子中,使用std::move()只是为了将一个值从左值变为右值,与拷贝无关。
void foo(Test &&t) {
}
template <typename T>
void fun(T &&v) {
}
int main() {
Test t1;
// foo(t1); //编译错误,不能绑定左值
foo(std::move(t1)); //将左值变为右值,编译通过
Test t2;
fun(t2); //编译通过,但不涉及到拷贝
fun(std::move(t2)); //编译通过,也不涉及到拷贝
return 0;
}
所以要涉及到拷贝,必须首先是值传递,也就是说把A通过拷贝给到B,这时候如果A是左值,那只能调用拷贝构造函数,而如果A是右值,那可以调用移动构造函数,程序员可以自己判断,如果一个左值再拷贝给另一个变量后,这个值没用了,那么可以在拷贝的地方写std::move(A)。
一般有下面几种情况:
放入容器中
std::vector<Test> vec;
vec.reserve(10);
Test t1;
vec.push_back(t1); //Copy Constructor....
Test t2;
vec.push_back(std::move(t2)); //Move Constructor...
注意move是会改变被move的对象的,如果被move对象为const,则依然调用拷贝构造函数。
函数实参列表
void foo(Test t) {
}
int main() {
Test t1;
foo(t1); //Copy Constructor....
Test t2;
foo(std::move(t2)); //Move Constructor....
return 0;
}
函数返回处
Test foo() {
std::vector<Test> vec;
vec.resize(1);
return vec.front(); //Copy Constructor....
}
Test fun() {
std::vector<Test> vec;
vec.resize(1);
return std::move(vec.front()); //Move Constructor....
}
int main() {
foo();
fun();
return 0;
}
进阶
利用通用引用+完美转发,实现左值-拷贝,右值 -移动的语义
35 class Other {
36 public:
37 template <typename T>
38 Other(T &&t) : t_{std::forward<T>(t)} {
41 }
42 private:
43 Test t_;
44 };
45 int main() {
46 Test t;
47 Other o1(t); //拷贝
49 Other o2(std::move(t)); //移动
50 return 0;
51 }