`this`的移动语义:如何基于*this的右值特性重载类成员函数以避免不必要拷贝?
如何基于
*this的值类别重载类成员函数 当然可以实现!C++11引入了成员函数的右值限定特性,完美解决你遇到的问题——不用全局函数,就能区分调用成员函数的对象是左值还是右值,从而分别实现拷贝和移动逻辑。
核心语法:成员函数的值类别限定
你可以在成员函数的参数列表后添加&或&&,来限定该函数只能被左值对象或右值对象调用:
&:该版本仅对左值对象可见&&:该版本仅对右值对象可见
改造你的代码
我们可以给sub_structure实现两个重载版本,分别处理左值和右值场景:
#include <vector> #include <utility> // 用于std::move class C { public: C(std::vector<int> data): data(std::move(data)) {} // 构造时移动优化,减少一次拷贝 // 左值版本:调用者是左值,拷贝元素(保证原对象数据不变) C sub_structure(const std::vector<size_t>& indices) & { std::vector<int> result; result.reserve(indices.size()); // 提前预留空间,避免多次扩容 for(auto i : indices) { result.push_back(data[i]); } return C(std::move(result)); // 移动构造返回值,减少额外拷贝 } // 右值版本:调用者是即将销毁的临时对象,直接移动元素 C sub_structure(const std::vector<size_t>& indices) && { std::vector<int> result; result.reserve(indices.size()); for(auto i : indices) { result.push_back(std::move(data[i])); // 移动而非拷贝元素,节省开销 } return C(std::move(result)); } std::vector<int> data; }; C f(){ return C({1,2,3,4}); } // 使用示例 int main() { // 左值对象调用:触发拷贝版本,原对象数据不受影响 C c_left({10,20,30}); C sub_left = c_left.sub_structure({0,2}); // 临时对象(右值)调用:触发移动版本,利用即将销毁的对象资源 C sub_right = f().sub_structure({1,3}); }
效果说明
- 当你调用
f().sub_structure(...)时,f()返回的是临时右值对象,编译器会自动匹配带&&的重载版本——此时临时对象马上就要被销毁,我们可以安全地移动它的data元素,完全避免不必要的拷贝开销。 - 当左值对象(比如
c_left)调用时,会匹配带&的版本,进行常规拷贝,保证原对象的data内容不受修改。
额外优化建议
- 把
indices参数改成const std::vector<size_t>&,避免不必要的参数拷贝。 - 构造函数里使用
std::move(data),利用右值引用优化构造过程。
内容的提问来源于stack exchange,提问作者Bubaya




