C++ 对象移动
右值和右值引用
左值可以位于赋值语句的左边,但右值不行,比如一个常量,只能出现在右边
通过 &&
获得右值引用,右值引用只能绑定到有个即将销毁的对象,因此可以将一个右值引用的资源
移动 到另一个对象中
1 | int i = 42; |
标准库 move
上面提到过不能将右值引用绑定到左值上,但可以显式地将左值转换为对应的右值引用类型,还可以通过
move
的新标准库函数来获得绑定到左值上的右值引用
1 |
|
int &&rr3 = std::move(rr1);
使用
std::move
函数将 rr1
的所有权转移给了
rr3
。这意味着 rr3
现在拥有了原本属于
rr1
的资源或对象。调用 move
意味着承诺:除了对
rr1
赋值或销毁它外,将不再使用它。
注意,std::move
函数并不实际移动对象,它只是将对象标记为可移动的。真正的移动操作是在移动构造函数或移动赋值运算符中执行的。
移动构造函数
1 | StrVec::StrVec(StrVec &&s) noexcept // 移动操作不会抛出任何异常 |
移动构造函数不分配任何新内存,而是接管给定的 StrVec
中的内存,接管内存后,将给定对象中的指针都置为
nullptr,这就完成了从给定对象的移动操作,此对象将继续存在。最终移后源对象会被销毁,意味着将在其上运行析构函数,如果忘记了改变
s.first_free
,则销毁移后源对象会释放掉我们刚刚移动的内存。
移动赋值运算符
1 | StrVec &StrVec::operator=(StrVec &&rhs) noexcept { |
移动迭代器
新标准库定义了移动迭代器适配器,通过调用
make_move_iterator
将一个普通迭代器转换为一个移动迭代器,一个迭代器的解引用运算符返回一个指向元素的左值,与其他迭代器不同,移动迭代器的解引用运算符生成一个右值引用
1 | auto last = uninitialized_copy(make_move_iterator(begin()), |
右值引用和成员函数
如果一个成员函数同时提供拷贝和移动版本,那么可以定义两个版本,一个是指向 const 的左值引用,第二个是指向非 const 的右值引用
1 | void push_back(const T&); // 拷贝,绑定到任意类型 T |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.