目录
1. 移动语义
移动语义可以使得编译器使用不那么昂贵的移动操作,来替换昂过的复制操作。同拷贝构造函数、拷贝赋值运算符赋予人们复制意义的能力一样,移动构造函数、移动赋值运算符也赋予人们移动语义的能力。更通俗的说:移动语义是通过移动构造函数或者移动赋值运算符实现的
移动语义的本质:所有权的转换!
举个例子,对于C++标准库提供的std::shared_ptr智能指针,当对其进行复制操作时,需要增加其引用计数,而引用计数是个原子类型,因此增加引用计数是个耗时操作;而当对其进行移动操作的时候,则引用计数会保持不变,也即无需进行引用计数的操作。
2. std::move的实现及使用
C++11中std::move强制将实参转换成右值引用的模板函数。其在C++11中的一个实现示例如下:
template <typename T>
typename std::remove_reference<T>::type&&
move(T&& param) {
using return_type = typename std::remove_reference<T>::type&&;
return static_cast<return_type >(param);
}
由上述实现可知,std::move是将参数强制转换成右值引用。而当某个参数被转换成右值引用后,便可以有机会通过移动构造函数或者移动赋值运算符进行移动操作。
下面以类A来进行说明其实现操作,类A的定义如下:
class A {
public:
A() {
std::cout << "A constructor" << std::endl;
}
A(const A& lhs) {
std::cout << "copy constructor" << std::endl;
}
A(A&& rhs) {
std::cout << "move constructor" << std::endl;
}
virtual ~A() {}
};
其测试代码以及测试结果如下:
int main() {
A a;
A b = a;
A c = std::move(a);
return EXIT_SUCCESS;
}
A constructor
copy constructor
move constructor
可以看到因为std::move将a转换成右值,因此此时c通过移动构造函数进行初始化。
思考一个问题:std::move()一定会导致移动发生么?
std::move不一定会保证移动操作的发生。
考虑下面这种情况,当我将上述测试代码中的A a声明成 const A a时,测试的结果会怎样?下面是测试的结果:
A constructor
copy constructor
copy constructor
原因就是,std::move的参数是个万能引用,当你传入一个const 对象的左值时,此时const属性依然会成为其参数的一部分,因此此时,移动构造函数便无法成为候选者,只有拷贝构造函数会成为候选者,故此时会调用拷贝构造函数,产生上述结果。
3. 总结
由上可知,C++11中的std::move 仅仅是将实参强制转换成右值引用,除此之外便没有任何作用。 而移动语义主要是由对象的移动构造函数或者移动赋值运算符实施。 并且std::move后并不能保证一定会实施移动语义
增加:
欢迎大家关注公众号互相交流(松元漫话)