C++抽象类Pokemon指针数组赋值后跨函数访问出现垃圾值如何解决
问题根源
你遇到的是典型的**悬垂指针(野指针)**问题:
pick_team()里定义的Charmander c1、Squirtle s1、Bulbasaur b1都是栈上的局部对象,生命周期仅在pick_team()函数执行期间有效- 函数执行结束返回后,这些局部对象占用的栈空间会被系统回收,
team数组里存储的指针就变成了指向无效内存的野指针,后续访问自然只能读到垃圾值 - 你在
pick_team()内部调用print_info()正常,是因为此时局部对象还没被销毁
修复方案
1. 修改pick_team()的赋值逻辑,用动态分配创建堆对象
把局部栈对象换成new创建的堆对象,堆对象的生命周期会持续到手动delete为止,不会随函数结束销毁:
void Trainer::pick_team(){ int p1, p2, p3; cout <<"Please choose which 3 pokemon you want in your team. Enter "<<endl; cout <<"1 for Charmander, 2 for Squirtle, or 3 for Bulbasaur."<<endl; cout <<"The first pokemon you pick will be your starter pokemon."<<endl; cout <<"1st pokemon: "; cin >> p1; cout <<"2nd pokemon: "; cin >> p2; cout <<"3rd pokemon: "; cin >> p3; // 给每个位置动态分配对应宝可梦对象 switch(p1) { case 1: team[0] = new Charmander(); break; case 2: team[0] = new Squirtle(); break; case 3: team[0] = new Bulbasaur(); break; default: team[0] = new Charmander(); // 非法输入默认给小火龙,可按需调整 } switch(p2) { case 1: team[1] = new Charmander(); break; case 2: team[1] = new Squirtle(); break; case 3: team[1] = new Bulbasaur(); break; default: team[1] = new Charmander(); } switch(p3) { case 1: team[2] = new Charmander(); break; case 2: team[2] = new Squirtle(); break; case 3: team[2] = new Bulbasaur(); break; default: team[2] = new Charmander(); } team[0]->print_info(); }
2. 补充Trainer类的析构函数释放内存,避免内存泄漏
堆对象需要手动释放,你需要给Trainer类加析构函数,在Trainer对象销毁时释放team里的所有宝可梦对象:
首先修改头文件trainer.h,添加析构函数声明:
class Trainer { private: string name; Pokemon* team[3]; public: void test(); void fight(); void heal_choice(); void swap(); void set_name(); void pick_team(); void comp_team(); Trainer(); ~Trainer(); // 新增析构函数声明 };
然后实现析构函数:
Trainer::~Trainer() { for(int i=0; i<3; i++) { delete team[i]; // 释放每个动态分配的宝可梦对象 team[i] = nullptr; // 置空避免野指针 } }
3. 额外注意事项
作为基类的Pokemon抽象类必须定义虚析构函数,否则通过Pokemon*指针删除子类对象时会触发未定义行为,示例:
class Pokemon { public: // 其他原有成员函数 virtual ~Pokemon() = default; // 新增虚析构函数 };
如果不需要实现Trainer对象的拷贝、赋值操作,可以直接禁用这两个函数避免浅拷贝导致的double free问题:
// 头文件Trainer类的public区域添加 Trainer(const Trainer&) = delete; Trainer& operator=(const Trainer&) = delete;
修改完成后,team数组里的指针指向的对象生命周期会和Trainer对象绑定,所有成员函数都可以正常访问宝可梦信息,不会再出现垃圾值的问题。
内容的提问来源于stack exchange,提问作者Taye
相关产品推荐
相关产品推荐

