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
相关产品推荐
相关产品推荐

