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

C++中new Mystring是否引发内存泄漏?无new写法报错解析

自定义Mystring类operator+重载的内存问题解析

说明:以下内容为课程练习场景,仅用于学习底层内存管理知识,不建议使用std::string替代。


一、带new的operator+是否存在内存泄漏?

先看你提供的带new的重载代码:

Mystring Mystring::operator+(const Mystring rhs) {
    Mystring *temp = new Mystring { *this };
    int a = strcat_s(temp->str, strlen(str) + strlen(rhs.str)+1, rhs.str);
    return (*temp);
}

结论:必然存在内存泄漏

  • 泄漏原因:new Mystring在堆上分配了一个Mystring对象,返回*temp时,会通过拷贝/移动构造创建一个临时对象返回给调用者,但堆上由temp指针指向的原始对象,没有任何代码会调用delete去释放它——函数结束后temp指针出作用域消失,再也无法定位到这个堆对象,导致这块内存永久无法回收。
  • 代码运行无错误的假象:程序结束后操作系统会回收所有进程占用的内存,所以不会触发运行时错误,但在程序运行期间,泄漏的内存一直被占用,属于隐性内存泄漏。

内存泄漏检测方法

  • 使用VS自带的CRT检测:在main函数末尾添加_CrtDumpMemoryLeaks();,程序结束后会在输出窗口显示泄漏的内存块详情。
  • 使用Valgrind(Linux/macOS):通过valgrind --leak-check=full ./your_program命令运行,会输出详细的泄漏报告。

二、无new的写法为什么触发堆损坏?

你尝试的无new代码:

Mystring Mystring::operator+(const Mystring rhs) {
    Mystring temp { *this };
    int a = strcat_s(temp.str, strlen(str) + strlen(rhs.str)+1, rhs.str);
    return (temp);
}

问题根源:内存越界写入

  • temp通过拷贝构造创建时,拷贝构造函数只为temp.str分配了原字符串长度+1的内存(比如原字符串是"FRANK",长度5,分配6字节)。
  • 调用strcat_s时,你传入的缓冲区大小是两个字符串总长度+1(5+5+1=11),但temp.str实际只有6字节空间。strcat_s会尝试写入超出已分配内存的区域,直接破坏堆结构,触发HEAP CORRUPTION DETECTED错误。
  • 这个问题和返回时的拷贝/移动操作无关,只要内存越界,后续的析构操作(释放内存)必然会触发错误。

三、不使用new的正确实现方式

当然存在,核心是先为合并后的字符串分配足够内存,再执行拷贝和拼接,以下是两种可行写法:

写法一:基于现有构造函数扩展

Mystring Mystring::operator+(const Mystring& rhs) const {
    // 计算合并后字符串的总长度(含终止符)
    size_t total_len = strlen(this->str) + strlen(rhs.str) + 1;
    
    // 创建临时对象,先释放默认构造的1字节内存
    Mystring temp;
    delete[] temp.str;
    // 分配足够容纳合并后字符串的内存
    temp.str = new char[total_len];
    
    // 拷贝当前对象字符串,再追加rhs的字符串
    strcpy_s(temp.str, total_len, this->str);
    strcat_s(temp.str, total_len, rhs.str);
    
    return temp;
}

写法二:用临时char数组中转

Mystring Mystring::operator+(const Mystring& rhs) const {
    size_t total_len = strlen(str) + strlen(rhs.str) + 1;
    // 先分配临时char数组存储合并后的字符串
    char* combined = new char[total_len];
    
    strcpy_s(combined, total_len, str);
    strcat_s(combined, total_len, rhs.str);
    
    // 用临时数组初始化Mystring对象,再释放临时数组
    Mystring temp(combined);
    delete[] combined;
    
    return temp;
}

关键注意点

  • 将参数改为const Mystring& rhs,避免不必要的拷贝,提升效率。
  • 成员函数添加const修饰,因为加法操作不应该修改当前对象。
  • 必须确保拼接前分配的内存足够容纳两个字符串加终止符,彻底避免内存越界。

内容的提问来源于stack exchange,提问作者Julian A. Tinao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:14:54