【问题标题】:Destructors and pointers to class attributes析构函数和指向类属性的指针
【发布时间】:2012-01-22 20:23:43
【问题描述】:

我有这个类 ChessBoard,这是它的标题:

class ChessBoard
{
    Field** board;
    Color currentColor; 

public:
    ChessBoard();
    ChessBoard(const ChessBoard&);
    Field* findField(std::string);
    ChessBoard& operator = (const ChessBoard&);

    bool checkIfFieldHasFigure(std::string);


    void writeOneState(SahApi*);
    void playAllMoves(std::istream*, SahApi*);
    void playMove(std::string);
    ~ChessBoard();

};

我有它的构造函数,它创建了棋盘的开始阶段:(很可怕,我知道 :))

ChessBoard::ChessBoard()
{
    int i, j;
    Error err;
    board = new Field*[8];
    if(!board)
    {
        err.writeToOutput(1);
        exit(1);
    }
    for(i = 0; i < 8; i++)
    {
        board[i] = new Field[8];
        if(!board[i])
        {
            err.writeToOutput(1);
            exit(1);
        }
    }
    currentColor = WHITE;
    char c;
    std::string s;
    Figure f;
    for(i = 0; i < 8; i++)
        for(j = 0; j < 8; j++)
        {
            s.clear();
            c = i + 'A';
            s.push_back(c);
            c = j + '1';
            s.push_back(c);
            board[i][j].position.assign(s);

            if((j > 1) && (j < 6))
                board[i][j].hasFigure = 0;
            else board[i][j].hasFigure = 1;

            if((i+j+2) % 2)
                board[i][j].color = WHITE;
            else board[i][j].color = BLACK;

            if( ((j==0)||(j==7)) && ((i==0)||(i==7)) )
            {
                Rook* r = new Rook(((j==0)?WHITE:BLACK), s);
                if(!r)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(r);
            }
            else if( ((i==1)||(i==6)) && ((j==0)||(j==7)) )
            {
                Knight* n = new Knight(((j==0)?WHITE:BLACK), s);
                if(!n)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(n);
            }
            else if( ((i==2)||(i==5)) && ((j==0)||(j==7)) )
            {
                Bishop* b = new Bishop(((j==0)?WHITE:BLACK), s);
                if(!b)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(b);
            }
            else if( (i==3) && ((j==0)||(j==7)))
            {
                Queen* q = new Queen(((j==0)?WHITE:BLACK), s);
                if(!q)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(q);
            }
            else if( (i==4) && ((j==0)||(j==7)) )
            {
                King* k = new King(((j==0)?WHITE:BLACK), s);
                if(!k)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(k);
            }
            else if( (j==1) || (j==6) )
            {
                Pawn* p = new Pawn(((j==1)?WHITE:BLACK), s);
                if(!p)
                {
                    err.writeToOutput(1);
                    exit(1);
                }
                board[i][j].putFigure(p);
            }
        }       
}

我还需要 ChessBoard 的析构函数,类似于:

ChessBoard::~ChessBoard()
{
    //for(int i = 0; i < 8; i++)
    //  delete board[i];
    delete [] board;
}

部分注释掉的原因是我的第一个问题:

1.为什么我不能用上面写的方法删除我所有的字段? 当我尝试这样做时,程序进入“块类型有效”错误,我知道这是由于试图删除不存在的内存造成的。当我将其注释掉时,该程序运行良好。 ChessBoard 是一个 8x8 矩阵,所以我应该可以像我在这里尝试的那样删除它。

我的第二个问题是:

2。如何删除我的 Chess Board 构造函数中存在的指向图形(King、Queen、Rook、...)的指针?这很令人困惑,因为这些指针被用作我的 Chess Board 的一部分,而我使用它们直到程序结束。当程序结束时,我需要释放我的内存,但我不知道如何访问这些指针。数字本身会被自动删除,因为它们都是非指针。 我什至需要删除那些指针,因为我一直使用它们直到最后,然后一切都被释放了吗?

【问题讨论】:

  • 这是作业吗?如果没有,为什么不使用适当的固定大小数组 (Field board[8][8];) 并省去动态内存管理容易出错的麻烦?
  • 没有必要检查 new 是否返回 NULL - 这永远不会发生。
  • 也不需要动态分配碎片或使用继承。如果您将此作为一个有趣的练习,请忽略我,但如果速度很重要(对于 AI 而言),枚举数组会快得多。

标签: c++ pointers memory-management constructor destructor


【解决方案1】:
  1. new/delete 的一般规则是调用必须相互匹配。你用

    创建你的板子
    board = new Field*[8];
    for(i = 0; i < 8; i++)
    {
        board[i] = new Field[8];
    }
    

    您将需要以相同的方式删除您的图板,但要倒退:

    for(i = 0; i < 8; i++)
    {
        delete [] board[i];
    }
    delete[] board;
    

    由于这不起作用,我猜您的问题是双重删除。其他东西正在释放阵列。您是否有可能拥有指向同一字段**的 ChessBoard 副本?

  2. 你将不得不以类似的方式删除你的数字。

    for (int x = 0; x < 8; x ++)
    for (int y = 0; y < 8 ;y ++)
    if (board[y][x] != NULL)
         delete board[y][x];
    

    只要您从板上删除图形的代码删除了该图形并将该图形的位置设置为 NULL,此代码就可以工作。

    2b。您的 2 问题的第二部分是您是否必须执行任何删除操作,因为程序即将结束。你是对的,因为如果你要立即退出,你不需要删除任何东西,操作系统无论如何都会为你释放所有的内存。

您通常应该这样做,通常您最终会修改大多数程序,允许它们运行多次,然后您会发生内存泄漏,因为每次运行都会使用稍微多一点的内存。


这就是如何解决您的问题。 但是,我强烈建议您更改大部分代码的样式并删除所有动态分配。

首先,使用常规静态大小的数组 (Field[8][8]) 来存储字段。我的意思是,国际象棋领域什么时候会改变大小?

其次,按值存储片段。如果片段在某个位置,则您的字段类已经存储。还让 Field 类也存储一个表示类型的枚举。 没有理由为您的作品使用动态分配。

第三,不需要检查new的返回是否为NULL。如果有错误,它会抛出一个异常,并且你的程序会停止(当然,当你内存不足时,你无能为力)。

【讨论】:

  • 非常感谢!不过,我对 ChessField 析构函数仍有疑问。也就是说,如果我将其更改为您建议的内容,例如:for(i =0;i&lt;8;i++){ delete [] board[i]; } delete [] board;,则程序运行完美,并且当它结束时出现错误(块类型有效)。我什至说(如果 board[i] != NULL),但它仍然给了我错误。
  • @Vidak Shoot,我的错误没有完全阅读这个问题。如果我不得不猜测它正在被双重删除。你有两个 ChessBoards 使用相同的数组或其他东西。
  • 不,我只有一个复制构造函数 defined 用于我的 ChessBoard,但我从不在任何地方使用它...我只有 ChessBoard 的一个实例,我使用它在整个程序中只有一次。另外,为什么if (board[i] != NULL) 子句没有解决这个问题?如果将其删除,它将为NULL,对吗?如果不是,它应该是可删除的?
  • 只有手动设置为 NULL 时才会变为 NULL。你是对的,有时人们会制作一个宏 safeDelete 或在删除后将其设置为 NULL 的东西。
  • 再次检查您的复制构造函数是否从未被调用。将其定义为立即退出或其他。
猜你喜欢
  • 2021-07-25
  • 2021-11-28
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
  • 1970-01-01
  • 2013-10-19
  • 1970-01-01
相关资源
最近更新 更多