如何强制使用拷贝赋值、拷贝构造而非移动操作?求反向std::move方案
这个问题问得非常到位!确实,当我们需要保持对象内存布局稳定(比如你提到的std::vector底层数组地址不能变,否则之前存的指针会失效),就需要绕过默认的移动操作,强制触发拷贝。其实思路很简单——既然*std::move()*是把左值转成右值引用来触发移动,那我们反过来,把右值转成左值引用来触发拷贝就行。
一、强制使用拷贝赋值运算符
针对你写的代码:
Object a(/*parameters 1*/); // 无法修改的代码,存储了&a[2]这类指针 a = Object(/*parameters 2*/); // 默认会调用移动赋值
要强制调用拷贝赋值,只需要把右边的临时对象(右值)转成const左值引用,这样编译器就会匹配接受const Object&参数的拷贝赋值运算符,而非接受Object&&的移动赋值。有两种简洁的写法:
- 使用
static_cast手动转换:
a = static_cast<const Object&>(Object(/*parameters 2*/));
- C++17及以后可以用
std::as_const(更直观):
#include <utility> // 引入std::as_const a = std::as_const(Object(/*parameters 2*/));
针对你的std::vector场景,这样修改后,如果原vector的容量大于等于新vector的大小,拷贝赋值会直接覆盖原数组的元素,底层数组地址完全不变,之前存储的&a[2]这类指针依然有效。
二、强制使用拷贝构造而非移动构造
类似地,如果要避免移动构造,比如本来这样会调用移动构造:
Object a(/*parameters 1*/); Object b(std::move(a)); // 默认移动构造
要强制拷贝构造,同样把右值转成const左值引用:
Object b(static_cast<const Object&>(std::move(a))); // 或者如果是临时对象: Object b(static_cast<const Object&>(Object(/*parameters*/)));
原理说明
为什么这样有效?因为C++的重载决议规则:
- 移动操作(移动构造/赋值)的参数是非const右值引用(
T&&),它只能绑定到非const的右值; - 拷贝操作(拷贝构造/赋值)的参数是const左值引用(
const T&),它可以绑定到左值、const右值,甚至非const右值。
当我们把右值转成const T&后,移动操作的参数(T&&)无法匹配这个类型,编译器就会选择拷贝操作。
另外,如果你觉得转引用的写法有点繁琐,也可以先把临时对象存为一个左值变量,再赋值/构造:
// 强制拷贝赋值的另一种写法 Object temp(/*parameters 2*/); a = temp;
不过这种写法会多创建一个命名的临时对象,不如转引用的方式简洁高效。
内容的提问来源于stack exchange,提问作者Jonn Dove
相关产品推荐
相关产品推荐

