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

为含AVL树嵌套结构的Team类编写拷贝构造等函数遇段错误

问题描述

我有一个Team类,内部包含两棵AVL树:一棵存储指向Player对象的shared_ptr,另一棵存储指向PlayerKeyId对象的shared_ptr。PlayerKeyId是Player的子类,仅重载了<和>运算符,用于按不同维度组织球队球员。

最初使用默认构造、拷贝构造和operator=时出现大量内存泄漏,自行编写这些函数后又出现段错误。相关代码及修复方案如下:


核心问题与修复要点

1. Node类的拷贝/赋值逻辑错误

  • 原拷贝构造中data = new T();属于冗余操作:T是shared_ptr<Player>这类值类型,直接data = oldNode.data即可完成安全拷贝。
  • 原拷贝构造仅浅拷贝子节点指针,会导致多个Node共享同一子树,析构时重复释放内存引发段错误,需改为递归深拷贝。
  • 原赋值运算符直接赋值指针属于浅拷贝,需补充内存释放与深拷贝逻辑,同时增加自赋值判断避免崩溃。
  • 析构函数无需手动置空parent,递归释放左右子节点即可。

2. AVLTree类的拷贝/赋值逻辑错误

  • 原拷贝构造仅浅拷贝根节点指针,需调用Node的拷贝构造完成整棵树的深拷贝。
  • 原赋值运算符直接共享根节点,需先释放旧树内存,再深拷贝新树。

3. Player类的拷贝/赋值问题

  • 默认构造未初始化followingPlayer和previousPlayer,导致野指针操作崩溃,需初始化为nullptr。
  • 拷贝构造需判断源指针是否为空,再深拷贝链表节点,避免空指针解引用。
  • 赋值运算符需先释放旧节点内存,再深拷贝新节点,同时增加自赋值判断。

4. Team类的拷贝/赋值问题

  • 拷贝构造与赋值运算符需先释放旧AVL树内存,再深拷贝新树,避免内存泄漏与重复释放。
  • 无需手动置空topScorer,智能指针会自动管理引用计数。

5. 简化建议

优先遵循Rule of Zero原则,用shared_ptr<Node<T>>管理AVL节点,避免手动编写拷贝/析构逻辑,减少内存错误。若必须手动管理内存,严格遵循Rule of Three:写了析构函数就必须配套正确的拷贝构造与赋值运算符。


修复后代码示例

Player类

class Player{
public:
    int playerID;
    int goals;
    int cards;
    int playerGamesPlayed;
    bool goalkeeper;
    Node<shared_ptr<Player>>* followingPlayer;
    Node<shared_ptr<Player>>* previousPlayer;
    shared_ptr<Team> playerTeamPointer;
    int teamPlayerId;

    Player(int playerID,int teamID, int gamesPlayed, int goals,int cards,bool goalkeeper,  shared_ptr<Team> playerTeamPointer)
        :playerID(playerID),goals(goals),cards(cards),playerGamesPlayed(gamesPlayed),goalkeeper(goalkeeper),playerTeamPointer(playerTeamPointer),teamPlayerId(teamID),
        followingPlayer(nullptr), previousPlayer(nullptr)
    {};
    
    ~Player(){
        delete followingPlayer;
        delete previousPlayer;
    };

    Player(const Player& p){
        playerID = p.playerID;
        goals = p.goals;
        cards = p.cards;
        playerGamesPlayed = p.playerGamesPlayed;
        goalkeeper = p.goalkeeper;
        teamPlayerId = p.teamPlayerId;
        playerTeamPointer = p.playerTeamPointer;
        followingPlayer = p.followingPlayer ? new Node<shared_ptr<Player>>(*p.followingPlayer) : nullptr;
        previousPlayer = p.previousPlayer ? new Node<shared_ptr<Player>>(*p.previousPlayer) : nullptr;
    }

    Player& operator=(const Player& p){
        if(this == &p) return *this;
        delete followingPlayer;
        delete previousPlayer;
        playerID = p.playerID;
        goals = p.goals;
        cards = p.cards;
        playerGamesPlayed = p.playerGamesPlayed;
        goalkeeper = p.goalkeeper;
        teamPlayerId = p.teamPlayerId;
        playerTeamPointer = p.playerTeamPointer;
        followingPlayer = p.followingPlayer ? new Node<shared_ptr<Player>>(*p.followingPlayer) : nullptr;
        previousPlayer = p.previousPlayer ? new Node<shared_ptr<Player>>(*p.previousPlayer) : nullptr;
        return *this;
    }

    Player() : followingPlayer(nullptr), previousPlayer(nullptr) {}
};

Team类

class Team{
public:
    int teamID;
    int points;
    int playerCount;
    int teamGames;
    shared_ptr<Player> topScorer;
    int totalGoals;
    int totalCards;
    int goalKeepers;
    bool valid;
    AVLTree<shared_ptr<PlayerKeyId>> *playersId;
    AVLTree<shared_ptr<Player>> *playersGoals;

    Team(int teamID, int points)
        :teamID(teamID),points(points),playerCount(0),teamGames(0),
        totalGoals(0),totalCards(0),goalKeepers(0),valid(false)
    {
        topScorer = make_shared<PlayerKeyId>(-1,-1,-1,-1,-1,false,nullptr);
        playersId = new AVLTree<shared_ptr<PlayerKeyId>>();
        playersGoals = new AVLTree<shared_ptr<Player>>();
    }

    Team(const Team& t){
        teamID = t.teamID;
        points = t.points;
        playerCount = t.playerCount;
        teamGames = t.teamGames;
        topScorer = t.topScorer;
        totalGoals = t.totalGoals;
        totalCards = t.totalCards;
        goalKeepers = t.goalKeepers;
        valid = t.valid;
        playersId = new AVLTree<shared_ptr<PlayerKeyId>>(*t.playersId);
        playersGoals = new AVLTree<shared_ptr<Player>>(*t.playersGoals);
    }

    Team& operator=(const Team& t){
        if(this == &t) return *this;
        delete playersId;
        delete playersGoals;
        teamID = t.teamID;
        points = t.points;
        playerCount = t.playerCount;
        teamGames = t.teamGames;
        topScorer = t.topScorer;
        totalGoals = t.totalGoals;
        totalCards = t.totalCards;
        goalKeepers = t.goalKeepers;
        valid = t.valid;
        playersId = new AVLTree<shared_ptr<PlayerKeyId>>(*t.playersId);
        playersGoals = new AVLTree<shared_ptr<Player>>(*t.playersGoals);
        return *this;
    }

    ~Team(){
        delete playersId;
        delete playersGoals;
    }
};

PlayerKeyId类

class PlayerKeyId:public Player{
public:
    using Player::Player;

    bool operator<(const PlayerKeyId& other) const {
        return playerID < other.playerID;
    }

    bool operator>(const PlayerKeyId& other) const {
        return playerID > other.playerID;
    }
};

AVL树相关类

template <class T>
class Node {
public:
    Node* left;
    T data;
    Node* right;
    int height;
    Node* parent;

    Node() : left(nullptr), right(nullptr), height(0), parent(nullptr) {}
    
    Node(const Node& oldNode) : height(oldNode.height), parent(nullptr) {
        data = oldNode.data;
        left = oldNode.left ? new Node(*oldNode.left) : nullptr;
        if(left) left->parent = this;
        right = oldNode.right ? new Node(*oldNode.right) : nullptr;
        if(right) right->parent = this;
    }

    Node& operator=(const Node& oldNode){
        if(this == &oldNode) return *this;
        delete left;
        delete right;
        data = oldNode.data;
        height = oldNode.height;
        parent = nullptr;
        left = oldNode.left ? new Node(*oldNode.left) : nullptr;
        if(left) left->parent = this;
        right = oldNode.right ? new Node(*oldNode.right) : nullptr;
        if(right) right->parent = this;
        return *this;
    }

    ~Node(){
        delete left;
        delete right;
    }
};
    
template <class T>
class AVLTree{
public:
    Node<T>* root;
   
    AVLTree() : root(nullptr) {}

    AVLTree(const AVLTree& oldAVL) {
        root = oldAVL.root ? new Node<T>(*oldAVL.root) : nullptr;
    }

    AVLTree& operator=(const AVLTree& oldAVL){
        if(this == &oldAVL) return *this;
        delete root;
        root = oldAVL.root ? new Node<T>(*oldAVL.root) : nullptr;
        return *this;
    }

    ~AVLTree(){
        delete root;
    }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:31:00