修复MyStr类浅拷贝导致重复释放内存的访问违例问题
修复C++中重复释放内存导致的访问违规异常
这个问题的核心是浅拷贝带来的重复内存释放:你的拷贝构造函数直接把原对象的strPtr指针值复制给新对象,导致两个MyStr实例共享同一块堆内存。当程序结束时,foo和foo2先后调用析构函数,第一次delete已经把这块内存归还给系统,第二次delete操作已经失效的内存地址,自然就触发了读访问违规异常。
下面是保留原有逻辑前提下的修复代码:
#include <iostream> #include <string> #include <windows.h> using namespace std; extern char MsgBuff[300]; class MyStr { string* strPtr; public: // "normal" constructor MyStr(const string& str) : strPtr(new string(str)) {} // destructor ~MyStr() { if(strPtr != nullptr) { // 用nullptr替代NULL,C++11及以上更规范 delete strPtr; strPtr = nullptr; // 置空避免野指针,是良好编程习惯 } } // 修复为深拷贝的拷贝构造函数 MyStr(const MyStr& x) : strPtr(new string(*x.strPtr)) { OutputDebugStringA("copy constructor"); } // 修正输出信息的移动构造函数 MyStr(MyStr&& x) : strPtr(x.strPtr) { x.strPtr = nullptr; OutputDebugStringA("move constructor"); // 原代码输出写错,修正为移动构造标识 } }; int main() { MyStr foo("Exam"); MyStr foo2 = foo; return 0; }
关键修改点说明:
- 深拷贝拷贝构造函数:不再直接复制指针,而是通过
new string(*x.strPtr)创建一块新的堆内存,把原对象字符串的内容完整复制进去。这样foo和foo2各自持有独立的内存块,析构时释放自己的内存,不会出现重复释放的冲突。 - 修正移动构造函数的输出:原代码里移动构造函数错误输出了"copy constructor",改成"move constructor"后,调试时能准确区分是触发了拷贝还是移动操作。
- 细节优化:把
NULL换成C++11引入的nullptr,类型更安全;析构时释放内存后将指针置空,避免出现野指针(虽然对象销毁后这个指针不会再被使用,但这是值得保持的编程习惯)。
内容的提问来源于stack exchange,提问作者Derek81
相关产品推荐
相关产品推荐

