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

C++中含shared_ptr的vector赋值运算符重载问题:拷贝游戏对象后打印副本崩溃排查

问题分析与解决方案

你遇到的崩溃大概率是因为缺少拷贝构造函数的实现,再结合其他潜在的代码问题共同导致的,咱们一步步拆解:

核心问题:拷贝初始化调用的不是赋值运算符

你主函数里的Game g2 = g1;是拷贝初始化操作,会调用Game的拷贝构造函数,而不是你重载的operator=。编译器自动生成的默认拷贝构造函数只会做逐成员浅拷贝:

  • vector<Pair>的拷贝是深拷贝,但Pair里的std::shared_ptr<Character>只会增加引用计数——这意味着g1和g2会共享同一个Character实例,完全不符合你想要的"副本与原对象独立"的深拷贝需求。
  • 如果Character的析构函数不是虚函数,或者Soldier的内部有未正确拷贝的动态资源,这种共享很容易引发内存访问错误,直接导致崩溃。

解决方案:实现拷贝构造函数

把你赋值运算符里的深拷贝逻辑复用过来,实现拷贝构造函数:

Game::Game(const Game& other) {
    std::vector<Pair> new_grid;
    for(int i=0; i < other.grid_characters.size(); i++){
        Character* character = other.grid_characters[i].character->clone();
        std::shared_ptr<Character> character_shared_ptr(character);
        Pair new_element( other.grid_characters[i].grid_point, character_shared_ptr);
        new_grid.push_back(new_element);
    }
    this->height = other.height;
    this->width = other.width;
    this->grid_characters = new_grid;
}

优化建议:使用拷贝交换Idiom

为了避免代码重复,同时自动处理自赋值问题,推荐用拷贝交换Idiom重构赋值运算符:

// 先实现一个swap成员函数
void Game::swap(Game& other) noexcept {
    std::swap(height, other.height);
    std::swap(width, other.width);
    std::swap(grid_characters, other.grid_characters);
}

// 赋值运算符通过传值调用自动触发拷贝构造,再交换数据
Game& Game::operator=(Game other) {
    swap(other);
    return *this;
}

其他潜在崩溃点检查

1. Character类必须有虚析构函数

如果Character的析构函数不是虚函数,std::shared_ptr<Character>销毁时只会调用基类析构函数,不会触发Soldier的析构逻辑,会导致Soldier的动态成员内存泄漏,甚至引发未定义行为。确保基类析构函数是虚函数:

class Character {
public:
    virtual ~Character() = default; // 必须是虚析构
    virtual Character* clone() const = 0;
    // ...其他成员
};

2. 检查getCharacterAtPoint函数的逻辑

你没给出这个函数的实现,但如果它遍历grid_characters时用了错误的循环条件(比如i <= game.grid_characters.size()),会直接导致数组越界访问,触发崩溃。确保循环只访问有效索引:i < game.grid_characters.size()。

3. 给Pair结构体添加默认构造函数

你的Pair只有带参数的构造函数,虽然当前代码不会触发问题,但后续如果对grid_characters做resize或无参数emplace_back操作,会编译失败。建议添加默认构造函数:

struct Pair {
    GridPoint grid_point;
    std::shared_ptr<Character> character;
    Pair() = default; // 添加默认构造
    Pair(GridPoint grid_point, std::shared_ptr<Character> character) 
        : grid_point(grid_point), character(character) {}
};

总结

先实现拷贝构造函数,再用拷贝交换Idiom优化赋值运算符,同时确保Character有虚析构函数,检查getCharacterAtPoint的循环逻辑,这些步骤应该能解决你的崩溃问题,同时实现正确的深拷贝。

内容的提问来源于stack exchange,提问作者SpaceNugget

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:02:29