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

C++自定义字符串类char*拷贝值为空、双重释放问题排查

问题核心原因

你遇到的重复释放、垃圾值、空值问题,本质是三个实现漏洞:

  • 浅拷贝导致多个对象的Input指针指向同一块堆内存,析构时多次触发free
  • 深拷贝逻辑没有为字符串结束符\0预留空间,或拷贝完成后未手动追加结束符,C风格字符串读取时会越界访问内存,出现垃圾值
  • 混淆了拷贝构造和赋值运算符的调用场景:CustomStringClass Obj2 = xxx是对象初始化语句,调用的是拷贝构造函数,不是赋值运算符,你之前只重载赋值运算符无法覆盖这个场景
    另外代码里存在拼写错误:Substirng应为Substring。
修复方案

不需要引入额外库函数,也不需要修改析构函数的free逻辑,按以下规则补全实现即可:

  • 所有申请堆内存存储字符串的场景,内存大小 = 字符串实际长度 + 1,多出来的1字节专门存结束符\0
  • 拷贝构造函数必须为新对象独立申请堆内存,逐字节复制源对象的字符串内容,最后手动追加结束符,禁止直接复制指针地址
  • 重载赋值运算符时先判断自赋值场景,释放当前对象原有内存后再申请新空间拷贝内容,避免内存泄漏和野指针
  • 所有字符串长度计算、内容拷贝逻辑通过手动遍历字符实现,不依赖库函数
完整修复后代码
class CustomStringClass 
{
private:
    char* Input;
    // 私有辅助函数,计算C风格字符串长度,不依赖第三方库函数
    int strLen(const char* s) {
        int len = 0;
        while(s[len] != '\0') len++;
        return len;
    }
public:
    // 普通构造函数
    CustomStringClass(const char* inputStr) {
        int len = strLen(inputStr);
        // 申请内存:长度+1用于存储结束符
        Input = (char*)malloc(len + 1);
        // 逐字节拷贝内容
        for(int i = 0; i < len; i++) {
            Input[i] = inputStr[i];
        }
        // 手动追加字符串结束符
        Input[len] = '\0';
    }

    // 深拷贝构造函数
    CustomStringClass(const CustomStringClass& other) {
        int len = strLen(other.Input);
        Input = (char*)malloc(len + 1);
        for(int i = 0; i < len; i++) {
            Input[i] = other.Input[i];
        }
        Input[len] = '\0';
    }

    // 深拷贝赋值运算符重载
    CustomStringClass& operator=(const CustomStringClass& other) {
        // 自赋值场景直接返回,避免释放自身内存后拷贝失败
        if(this == &other) {
            return *this;
        }
        // 释放当前对象原有内存,避免内存泄漏
        free(Input);
        int len = strLen(other.Input);
        Input = (char*)malloc(len + 1);
        for(int i = 0; i < len; i++) {
            Input[i] = other.Input[i];
        }
        Input[len] = '\0';
        return *this;
    }

    CustomStringClass Substring(int Start, int End) {
        // 计算子串实际长度
        int subLen = End - Start + 1;
        // 申请临时缓冲区存储截取的子串
        char* subBuf = (char*)malloc(subLen + 1);
        for(int i = 0; i < subLen; i++) {
            subBuf[i] = Input[Start + i];
        }
        subBuf[subLen] = '\0';
        CustomStringClass temp(subBuf);
        // 释放临时缓冲区,避免泄漏
        free(subBuf);
        return temp;
    }

    // 测试用接口,返回内部存储的字符串
    const char* c_str() {
        return Input;
    }

    ~CustomStringClass(){
        free(this->Input);
    }
};

int main()
{
    CustomStringClass Obj1("Hello");
    CustomStringClass Obj2 = Obj1.Substring(2,3);
    // 此时Obj2.c_str()输出结果为"ll",无重复释放、无内存泄漏、无垃圾值
    return 0;
}
验证说明
  • 所有对象的Input指针都指向独立的堆内存,析构时各自释放自身申请的内存空间,不会出现重复释放问题
  • 所有字符串都手动追加了\0结束符,不会出现越界读取导致的垃圾值、空值问题
  • 没有引入额外头文件和库函数,所有字符串操作均通过手动遍历实现
  • 析构函数的free逻辑完全保留,未做注释或修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:30:44