C++退出函数时std::string内存释放失败问题咨询
问题根因分析
你给出的最小复现代码的错误本质是非POD(普通旧数据)类型的非法二进制序列化操作:std::string 不属于可以直接做内存拷贝的纯值类型,内部维护了指向堆内存的字符指针、字符串长度、容量等私有成员。你直接对std::string对象本身执行二进制读写output.write((char*)&a, sizeof(a)),仅能写入对象本身占用的栈/成员内存(也就是指针、长度、容量这几个值),完全不会写入指针指向的实际字符串内容。
当你第二次运行仅执行读取逻辑时,相当于直接把上一次运行进程中string a的内部成员值(包括已经失效的堆地址指针)直接覆盖到当前进程的string b的内部结构上:
- 篡改了
b原本合法的内部内存指针 - 后续
b被析构时会尝试释放这个不属于当前进程的无效地址,直接触发内存错误,这就是你看到的报错出现在std::string name;声明行附近的核心原因,和你猜测的「字符串共享引用」没有关系。
你最初提到的类成员vector存string触发释放报错的问题,本质也是同类错误:大概率你存在直接memcpy结构体、直接二进制读写vector元素、或者内存越界写篡改string内部结构的操作,导致string内部的指针失效,析构时触发崩溃。
正确的std::string序列化写法
如果要二进制存储字符串,需要先存储字符串长度,再存储对应长度的实际字符内容,读取时按对应逻辑解析即可,参考示例:
#include <iostream> #include <fstream> #include <string> using namespace std; int main () { // 写入逻辑 string a = "something"; ofstream output("a.dat", ios::out|ios::binary); size_t len = a.size(); output.write((char*)&len, sizeof(len)); // 先写长度 output.write(a.c_str(), len); // 再写实际字符 output.close(); // 读取逻辑 ifstream input("a.dat", ios::in|ios::binary); size_t read_len = 0; input.read((char*)&read_len, sizeof(read_len)); // 先读长度 string b(read_len, '\0'); // 提前申请对应长度的空间 input.read(&b[0], read_len); // 读入对应长度的字符 input.close(); cout << b << endl; // 验证读取结果 return 0; }
其他排查建议
- 检查业务代码中是否存在对
std::string、std::vector等STL容器直接做memcpy、二进制读写、强制指针类型转换篡改内部结构的操作 - 检查是否存在数组越界、野指针写入的逻辑,这类内存越界操作很容易篡改相邻的string对象内部成员,触发同类崩溃
内容的提问来源于stack exchange,提问作者jfo420
相关产品推荐
相关产品推荐

