C++临时对象内存释放异常:自定义字符串类运算符实现排查
问题分析与修复方案
你的核心问题出在**operator+=没有正确重新分配内存**,直接在原数组末尾写入超出容量的数据,导致堆内存损坏,后续临时对象析构时执行delete[]触发未定义行为(表现为阻塞)。另外代码里还有几个细节问题也需要修正,下面一步步解决:
1. 修复operator+=的内存分配逻辑
当前的operator+=直接把新字符串拷贝到p + this->size()的位置,但原数组的容量只有data_length + 1(存储原字符串加\0),根本没有空间容纳新内容,这会造成堆越界写入,破坏堆结构,最终导致析构时delete[]出错。
正确的实现应该:
- 计算拼接后的总长度
- 分配足够的新内存
- 复制原字符串和要追加的字符串到新内存
- 释放旧内存,更新指针和长度
修改后的operator+=:
Str& Str::operator+=(const Str &s) { // 计算新的总长度 size_type new_length = data_length + s.data_length; // 分配新内存,+1是为了存储'\0' char* new_p = new char[new_length + 1]; // 复制原字符串内容 std::copy(p, p + data_length, new_p); // 复制要追加的字符串内容 std::copy(s.p, s.p + s.data_length, new_p + data_length); // 添加字符串结束符 new_p[new_length] = '\0'; // 释放旧内存 delete[] p; // 更新成员变量 p = new_p; data_length = new_length; return *this; }
2. 修正其他潜在问题
(1)默认构造函数初始化指针
默认构造函数里p没有初始化,会导致uncreate()里的delete[] p操作野指针,触发未定义行为。修改默认构造函数:
Str() : p(nullptr), data_length(0) {};
(2)修正end()方法的实现
原来的end()调用std::strlen(p),这不仅效率低(每次都要遍历字符串),还会在字符串包含\0时返回错误的长度。应该直接用data_length:
iterator end() { return p + data_length; } const_iterator end() const { return p + data_length; }
(3)修正赋值运算符的参数
operator=(Str& rhs)的参数应该是const Str&,否则无法接收临时对象(比如operator+返回的临时对象),修改为:
Str& operator=(const Str& rhs)//assignment operator { if (&rhs != this) { uncreate(); create(rhs.size()); std::copy(rhs.begin(), rhs.end(), p); p[data_length] = '\0'; } return *this; }
(4)完善uncreate()方法
确保uncreate()后p被置为nullptr,避免重复释放:
void Str::uncreate() { delete[] p; p = nullptr; // 置空指针 data_length = 0; }
3. 验证修复后的代码
修改后的完整代码可以正确执行字符串拼接,临时对象析构时也不会出现阻塞。测试你的main函数:
int main() { Str s1 = "hello"; Str s2 = "worly"; Str s3 = s1 + s2; // 可以添加输出验证:std::cout << s3.c_str() << std::endl; return 0; }
额外说明
- 你还可以实现移动构造函数和移动赋值运算符,提升
operator+的效率(避免不必要的拷贝)。 - 注意遵循三/五法则:因为你自定义了析构函数,必须正确实现拷贝构造、拷贝赋值,最好加上移动构造和移动赋值。
内容的提问来源于stack exchange,提问作者axcelenator
相关产品推荐
相关产品推荐

