C++类对象赋值拷贝后原对象销毁,访问指针成员指向内容输出乱码
问题根本原因
你的问题是典型的浅拷贝导致的野指针访问,属于C++类资源管理的常见错误:
- 你没有自定义拷贝赋值运算符,编译器生成的默认拷贝赋值运算符只会对成员变量做逐字节复制:执行
r2 = r1时,直接把r1的_history指针的内存地址复制给了r2的_history,此时r1和r2的_history指向同一块堆内存。 - 当r1离开作用域被析构时,析构函数直接
delete了这块共享的堆内存,r2的_history就变成了野指针,后续访问这块已经被释放的内存属于未定义行为,就会输出随机数,甚至直接崩溃。 - 你只自定义了拷贝构造函数没用,拷贝构造函数只在对象新建时调用,
r2 = r1是赋值操作,走的是拷贝赋值运算符的逻辑,你没自定义的话还是用编译器生成的浅拷贝版本。
修复方案
有两种常见的修复方式,推荐优先选第一种:
方案1:直接去掉指针,用值类型存储(最省心)
std::vector本身就是封装了动态内存管理的容器,根本没必要用指针包裹,直接把成员改成std::vector<int> _history,所有构造函数、析构函数都不用手动管理内存,编译器生成的默认拷贝、赋值逻辑都是安全的深拷贝,完全不会出现野指针问题。
修改后的头文件关键代码:
class Robot{ private: int workUnit = 0; std::vector<int> _history; // 去掉指针,直接存vector public: Robot() : name("DEFAULT") {}; // 不用手动new分配内存 Robot(const std::string& name) : name(name){}; ~Robot(){std::cout << name << ": Goodbye!" << std::endl; }; // 不用手动delete释放内存 // 其余成员函数把指针调用->改成普通调用.即可 void work(){ workUnit++; _history.push_back(workUnit); std::cout << name << " is working. > " << workUnit <<"\n"; } // 其余代码逻辑保持不变即可 };
方案2:遵守三五法则,手动实现深拷贝逻辑
如果你确实有特殊需求必须用指针存储,就要同时实现拷贝构造函数、拷贝赋值运算符、析构函数(C++11及以上还可以补充移动构造、移动赋值),保证资源拷贝是深拷贝,同时避免内存泄漏:
首先在头文件中声明拷贝构造和拷贝赋值:
class Robot{ // 其余原有成员保持不变 public: // 已有构造、析构函数 Robot(const Robot& other); // 拷贝构造函数声明 Robot& operator=(const Robot& other); // 拷贝赋值运算符声明 };
然后实现对应的逻辑:
// 拷贝构造函数实现 Robot::Robot(const Robot& other) { name = other.name; workUnit = other.workUnit; // 重新分配内存,复制原对象vector的全部内容 _history = new std::vector<int>(*other._history); } // 拷贝赋值运算符实现,注意要先释放自身原有资源避免内存泄漏 Robot& Robot::operator=(const Robot& other) { if (this == &other) { // 先判断自赋值场景,直接返回 return *this; } // 释放自身原来持有的_history内存 delete _history; // 复制所有成员数据 name = other.name; workUnit = other.workUnit; _history = new std::vector<int>(*other._history); return *this; }
内容的提问来源于stack exchange,提问作者mathewsjoyy
相关产品推荐
相关产品推荐

