Массив объектов, поврежденных после использования cout

#c #arrays #oop #pointers

Вопрос:

После нескольких дней, когда мой вопрос был закрыт, и мои правки, которые отвечали бы на все вопросы в комментариях, которые не были одобрены, я решил повторно опубликовать с несколькими изменениями.

Я новичок в c , но я опытный программист. Я пытаюсь создать шахматный движок, как я сделал это на python, но я хочу, чтобы это было быстрее. Я храню свою шахматную доску в виде 2d-массива указателей фигур.

Шахматная доска.h

 #include <iostream>
#include "pieces.h"

class Chess
{
private:
    Piece* board[8][8] = {};
public:
    Chess();
    void print_board();
};
 

штук.ч

 enum PieceType {
    pawn, knight, bishop, rook, queen, king
};

enum Colour {
    white, black
};

class Piece {
protected:
    PieceType pieceType;
    Colour colour;
public:
    char symbol;
    Piece(Colour colour);
};

class Pawn : public Piece {
public:
    Pawn(Colour colour);
};

// The rest of the pieces are defined in the same way
 

pieces.cpp

 #include "pieces.h"

Piece::Piece(Colour colour) {
    this->colour = colour;
}

Pawn::Pawn(Colour colour) : Piece(colour) {
    this->pieceType = pawn;
    this->symbol = (colour == white) ? 'P' : 'p';
}

// The rest of the pieces constructors are the same 
 

chessBoard.cpp

 Chess::Chess()
{
    // The back row of black pieces
    Rook bq_r(black);
    Knight bq_n(black);
    Bishop bq_b(black);
    Queen bq_q(black);
    King bk_k(black);
    Bishop bk_b(black);
    Knight bk_n(black);
    Rook bk_r(black);

    board[0][0] = amp;bq_r;
    board[0][1] = amp;bq_n;
    board[0][2] = amp;bq_b;
    board[0][3] = amp;bq_q;
    board[0][4] = amp;bk_k;
    board[0][5] = amp;bk_b;
    board[0][6] = amp;bk_n;
    board[0][7] = amp;bk_r;
}

void Chess::print_board() {
    for (int i = 0; i < 8; i  ) {
        for (int j = 0; j < 8; j  ) {
            if (board[i][j]) {
                std::cout << board[i][j]->symbol;
                std::cout << " ";
            } else {
                std::cout << ". ";
            }
        }
        std::cout << std::endl;
    }
}
 

main.cpp

 #include "chessBoard.h"

int main()
{
    Chess chess;
    chess.print_board();
    return 1;
}
 

Я понимаю, что это много кода, и я хотел бы опубликовать только соответствующую информацию, но, к сожалению, я понятия не имею, в чем была проблема, и большинство комментариев к моему последнему сообщению просили предоставить дополнительную информацию. Если вам нужен полный код, его можно найти здесь: https://github.com/kiran-isaac/chess-engine/tree/test.

Ожидаемый Результат

 r n b q k b m r 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
 

Фактический Результат

 r   �   � � � r 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
 

Первая ладья всегда верна. Все последующее меняется с каждым запуском программы.

Причина, по-видимому, в том, что все в массиве платы повреждено. Все в порядке, пока не появится функция «Печатная плата». Как только он сталкивается с первым cout, все в массиве становится поврежденным. Я могу обойти это, сохранив выходные данные в строке и выведя послесловие, но это все равно приведет к повреждению массива, хотя и после того, как я успешно распечатал его.

Я надеюсь, что кто-нибудь сможет помочь, так как мне нравится разработка на c , и я не хочу отказываться от этого проекта.

Это скриншот значения массива платы из строки 1 функции printBoard (). Так и должно быть.

Снимок экрана с момента, когда он работает

Это снимок экрана, сделанный после первой итерации, после обнаружения std::cout в строке 4 функции printBoard ().

Снимок экрана после того, как он не

Я застрял на этой проблеме на 2 дня, исследуя и отлаживая, и ничего не нашел. Я уверен, что это что-то простое, что я делаю неправильно, я просто не могу этого найти. Пожалуйста, прокомментируйте, если вам нужна дополнительная информация.

Спасибо

Комментарии:

1. На первый взгляд вам кажется, что вы записываете адреса временных объектов. Это УБ. Я предполагаю, что при вызове std::cout::operator<< он перезаписывает кадр стека конструктора и, следовательно, ваши конкретные объекты. Используйте интеллектуальные указатели и динамическое выделение (или переменные членов)

2. Исходя из Python, вы, вероятно, захотите потратить некоторое время на чтение о времени жизни объектов . Особенно автоматическое хранение . C требует, чтобы вы думали о том, как и когда объекты достигают своего конца жизни.

3. Спасибо. Можно ли было бы опубликовать это в качестве ответа с примером того, как я это сделаю?

4. Вам не хватает защитников заголовка, а также полного определения заголовка Chess .

5. Я забыл сделать это публичным, извините

Ответ №1:

Принятый ответ устраняет проблему времени жизни объекта, используя динамическое распределение для создания объектов кучи, но следует отметить, что полиморфизм указателя базового класса не требует динамического распределения (я предполагаю, что вы собираетесь добавить virtual функции позже).

Различные производные части могут быть просто элементами данных Chess объекта, что часто обеспечивает лучшую производительность и меньше подводных камней, чем динамическое распределение (правильное перемещение указателей по доске также может быть излишне громоздким unique_ptr ).:

 class Chess {
private:
    Piece* board[8][8] = {};

    Rook m_white_rook;
    Knight m_white_knight;
    // ...all pieces here...

public:
    Chess() : 
        m_white_rook(Colour::white), 
        m_white_knight(Colour::white),
        // ...initialize pieces here...
    {
        board[0][0] = amp;m_white_rook;
        board[0][1] = amp;m_white_knight;
        // ...assign simple, non-owning pointers to the board...
    }
};
 

Комментарии:

1. Спасибо, это, вероятно, лучшее решение в данном случае. Однако я собираюсь использовать первый, так как мне нужно научиться делать такие вещи

Ответ №2:

Объекты bq_r и т. Д., Определенные в вашем Chess::Chess() конструкторе, Имеют срок службы, заканчивающийся после завершения работы конструктора, поэтому массив полон висячих указателей, которые нельзя использовать должным образом.

Я бы рекомендовал вместо этого:

 #include <memory>

class Chess
{
private:
    std::unique_ptr<Piece> board[8][8] = {};
public:
    Chess();
    void print_board();
};

Chess::Chess()
{
    board[0][0] = std::make_unique<Rook>(black);
    board[0][1] = std::make_unique<Knight>(black);
    board[0][2] = std::make_unique<Bishop>(black);
    board[0][3] = std::make_unique<Queen>(black);
    board[0][4] = std::make_unique<King>(black);
    board[0][5] = std::make_unique<Bishop>(black);
    board[0][6] = std::make_unique<Knight>(black);
    board[0][7] = std::make_unique<Rook>(black);

    for (autoamp; pawn_pos : board[1])
         pawn_pos = std::make_unique<Pawn>(black);

    // ...
}
 

Так unique_ptr как s очистится, удалив указатель на базовый класс Piece , который на самом деле указывает на другие типы классов, этому классу нужен виртуальный деструктор:

 class Piece {
public:
    // ...
    virtual ~Piece() = defau<
};
 

Комментарии:

1. Piece у него нет virtual деструктора, поэтому вы, возможно, захотите добавить это к ответу.

2. Спасибо, я и не подозревал, насколько сложнее c , чем python!