You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中结合Move semantics与this指针实现高效不可变对象?

结合移动语义实现高效不可变字符串对象

要实现你的需求,核心是利用C++11引入的成员函数引用限定符,它能让编译器根据调用对象的左值/右值属性自动选择对应的成员函数版本。以下是具体实现思路和修正后的代码:

核心思路

  • 给append方法添加引用限定符,区分两种调用场景:
    • 左值对象(具名变量,如a)调用const &限定的append,返回新创建的字符串,保证原对象不可变
    • 右值对象(临时对象、被std::move转换的对象)调用&&限定的append,直接修改当前对象并返回它,利用移动语义避免不必要的拷贝

修正后的完整代码

#include <iostream>
#include <cstring>
#include <utility> // 用于std::move

class string {
    char* data;

    // 辅助函数:获取字符串长度,避免重复调用strlen
    size_t size() const {
        return data ? std::strlen(data) : 0;
    }

public:
    // 构造函数
    string(const char* p) {
        size_t len = std::strlen(p) + 1;
        data = new char[len];
        std::memcpy(data, p, len);
    }

    // 析构函数
    ~string() {
        delete[] data;
    }

    // 拷贝构造
    string(const string& that) {
        size_t len = that.size() + 1;
        data = new char[len];
        std::memcpy(data, that.data, len);
    }

    // 移动构造
    string(string&& that) noexcept : data(that.data) {
        that.data = nullptr;
    }

    // 左值对象调用的append:返回新对象,不修改原对象
    string append(const char* p) const & {
        std::cout << "copy" << std::endl;
        size_t total_len = size() + std::strlen(p) + 1;
        char* new_data = new char[total_len];
        std::strcpy(new_data, data);
        std::strcat(new_data, p);
        return string(new_data); // 利用私有构造优化内存分配
    }

    // 右值对象调用的append:修改当前对象,返回自身的右值引用
    string&& append(const char* p) && {
        std::cout << "move" << std::endl;
        size_t total_len = size() + std::strlen(p) + 1;
        char* new_data = new char[total_len];
        std::strcpy(new_data, data);
        std::strcat(new_data, p);
        
        delete[] data;
        data = new_data;
        
        return std::move(*this);
    }

private:
    // 私有构造:直接接收已分配的char*,避免重复分配内存
    explicit string(char* new_data) : data(new_data) {}
};

int main() {
    string a("a");
    string b = a.append("...");           // 调用copy版本
    string c = a.append("1...").append("2..."); // 先copy,再move
    string d = string("s").append("1...").append("2..."); // 两次move

    return 0;
}

关键细节说明

  1. 成员函数引用限定符:
    • const &限定:仅左值对象可调用,保证原对象不被修改,符合不可变性要求
    • &&限定:仅右值对象可调用,允许修改当前对象,因为右值对象后续不会再被使用
  2. 右值版本返回值:返回string&&而非string&,确保链式调用时仍能识别为右值,继续使用移动版本
  3. 私有构造优化:新增的string(char*)构造函数避免临时对象的二次内存分配,提升效率
  4. noexcept移动构造:标记移动构造为noexcept,让编译器更安全地优先使用移动语义而非拷贝

预期输出

运行代码后,控制台将输出:

copy
copy
move
move
move

完全符合你预期的调用逻辑。

内容的提问来源于stack exchange,提问作者Jean-Luc Delarbre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:10:26