You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

`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内容不受修改。

额外优化建议

  1. indices参数改成const std::vector<size_t>&,避免不必要的参数拷贝。
  2. 构造函数里使用std::move(data),利用右值引用优化构造过程。

内容的提问来源于stack exchange,提问作者Bubaya

火山引擎 最新活动