在C++值取向属性的setter中使用std::move()有哪些陷阱?
相关问题解答
1. 按值传递参数是否一定会生成深拷贝?
答案是不会,该特性完全由对象的具体实现决定。
- C++中类型的拷贝行为由自身的拷贝构造函数定义:如果类型的拷贝构造函数实现的是深拷贝逻辑,按值传递时才会生成深拷贝;如果自定义拷贝构造用了浅拷贝逻辑(比如仅复制指针地址、不复制指针指向的资源),按值传递就只会做浅拷贝。
- 甚至很多场景下按值传递连拷贝都不会发生:
- 当传入的参数是右值(比如临时对象、被
std::move标记的左值)时,参数会优先调用类型的移动构造函数完成初始化,而非拷贝构造,对于管理堆资源的类型而言移动通常是浅拷贝(仅转移资源所有权)。 - 编译器满足条件时会触发拷贝消除优化,直接将对象构造在参数的内存位置,完全省略拷贝/移动操作。
- 当传入的参数是右值(比如临时对象、被
2. 该setter写法是否会意外修改调用方的原入参对象?
答案是不会,调用方的原对象不会受到setter内部std::move的影响。
- 因为参数
X x是按值传递的,进入setter函数时的x已经是和调用方原对象完全独立的副本:- 如果调用方传入的是普通左值对象,参数
x是原对象的拷贝,setter内部std::move作用在这个副本上,原对象的状态完全不受影响。 - 如果调用方主动传入
std::move(原对象),那么参数x是通过移动原对象构造得到的,此时原对象的状态在进入setter前就已经变成移后可销毁状态,和setter内部的std::move无关。
- 如果调用方传入的是普通左值对象,参数
补充:该setter写法的适用场景
这种写法是C++11之后比较常用的简化写法,优势是仅需维护一个重载,即可同时兼容左值、右值入参,对于支持高效移动的类型,性能和单独写const X&+X&&两个重载的版本几乎一致,代码更加简洁。
仅当你的类型不支持移动、且拷贝成本很高时,这种写法才会比传const引用的版本多一次拷贝构造的开销,此时可以考虑换用双重载的实现。
内容的提问来源于stack exchange,提问作者Marty Cagas
相关产品推荐
相关产品推荐

