C++类深拷贝赋值运算符实现问题及VS调试无法步入求助
C++深拷贝未生效且赋值运算符未被调用的问题排查与修复
核心问题:指针赋值未触发对象赋值运算符
你的测试代码中copyTrophy = newTrophy;是指针变量的赋值,只是让copyTrophy指针指向了newTrophy指针所指向的同一个Trophy对象内存地址,完全没有调用你重载的operator=。这就是为什么修改原对象后拷贝对象跟着变,以及调试进不去赋值运算符的原因——这个方法根本没被执行过。
正确的对象赋值方式
把指针赋值改成对象的赋值操作,直接操作指针指向的对象:
// 替换原来的 copyTrophy = newTrophy; *copyTrophy = *newTrophy;
或者更简洁的方式,直接使用拷贝构造函数创建拷贝对象,避免多余的默认构造调用:
// 不需要先new默认构造的对象,直接用拷贝构造 Trophy* copyTrophy = new Trophy(*newTrophy);
赋值运算符的缺陷修复
你当前的operator=存在两个严重问题:
- 未释放当前对象已有的动态内存:直接给
name、level、color赋新的new出来的指针,原来的指针指向的内存会丢失,造成内存泄漏。 - 未处理自赋值情况:如果出现
obj == this的自赋值,会先释放内存再拷贝,导致非法访问。
修复后的赋值运算符:
Trophy& Trophy::operator=(const Trophy& obj){ // 先处理自赋值 if (this == &obj) { return *this; } // 释放当前对象已有的动态内存 delete name; delete level; delete color; // 深拷贝新的内存 name = new string(*obj.name); level = new int(*obj.level); color = new Color(*obj.color); return *this; }
必须补充的析构函数
你的类成员都是动态分配的内存,但没有提供析构函数来释放这些内存,会导致程序运行时持续泄漏内存。添加析构函数:
Trophy::~Trophy() { delete name; delete level; delete color; }
补充拷贝构造函数(可选但推荐)
为了完整遵循三法则(如果重载了赋值运算符、析构函数,就需要拷贝构造函数),建议实现拷贝构造函数,确保通过拷贝构造创建对象时也能完成深拷贝:
Trophy::Trophy(const Trophy& obj) { // 深拷贝成员 name = new string(*obj.name); level = new int(*obj.level); color = new Color(*obj.color); }
测试代码修改后的完整示例
修改后的主函数:
#include <iostream> #include <string> using namespace std; enum Color { BRONZE, SILVER, GOLD }; class Trophy { private: string* name = new string; int* level = new int; Color* color = new Color; public: Trophy(); Trophy(const Trophy& obj); ~Trophy(); Trophy& operator=(const Trophy& obj); void setName(const string& n) { *name = n; } void setLevel(int l) { *level = l; } void setColor(Color c) { *color = c; } string getName() const { return *name; } int getLevel() const { return *level; } Color getColor() const { return *color; } }; // 构造函数 Trophy::Trophy() { *name = ""; *level = 0; *color = BRONZE; } // 拷贝构造函数 Trophy::Trophy(const Trophy& obj) { name = new string(*obj.name); level = new int(*obj.level); color = new Color(*obj.color); } // 析构函数 Trophy::~Trophy() { delete name; delete level; delete color; } // 修复后的赋值运算符 Trophy& Trophy::operator=(const Trophy& obj){ if (this == &obj) { return *this; } delete name; delete level; delete color; name = new string(*obj.name); level = new int(*obj.level); color = new Color(*obj.color); return *this; } int main() { Trophy* newTrophy = new Trophy(); newTrophy->setName("My Trophy"); newTrophy->setLevel(10); newTrophy->setColor(GOLD); cout << newTrophy->getName() << " " << newTrophy->getLevel() << " " << newTrophy->getColor() << endl; // 使用拷贝构造创建拷贝对象 Trophy* copyTrophy = new Trophy(*newTrophy); // 或者使用赋值运算符: // Trophy* copyTrophy = new Trophy(); // *copyTrophy = *newTrophy; cout << copyTrophy->getName() << " " << copyTrophy->getLevel() << " " << copyTrophy->getColor() << endl; newTrophy->setName("Please work"); newTrophy->setLevel(5); newTrophy->setColor(SILVER); cout << newTrophy->getName() << " " << newTrophy->getLevel() << " " << newTrophy->getColor() << endl; cout << copyTrophy->getName() << " " << copyTrophy->getLevel() << " " << copyTrophy->getColor() << endl; // 记得释放动态分配的对象,避免内存泄漏 delete newTrophy; delete copyTrophy; return 0; }
运行这个修改后的代码,修改原对象后,拷贝对象的内容不会跟着改变,且赋值运算符会被正常调用,调试时可以步入该方法。
内容的提问来源于stack exchange,提问作者erica_on_strike
相关产品推荐
相关产品推荐

