You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 13:54:08