如何制作指针数组的深拷贝

How to make a deep copy of an array of pointers

我正在创建国际象棋引擎,我正在使用可以找到的国际象棋引擎 here 因为它是 ChessBoard 和 Piece classes。作为引擎的一部分,我必须对 ChessBoard class 的实例进行深度复制,而且我在执行此操作时遇到了很大的困难。我尝试以多种方式编辑 class 中的复制构造函数并更改我自己的代码,但无济于事。

这是我的代码中有问题的部分:

move_list = j->data().board->getPossibleMoves(board->flip(colour));
for (auto k : move_list) {
    print_board(j->data().board);
    current_node.board = j->data().board;
    current_node.board->moveTo(std::tuple<char, char>(std::get<0>(k), std::get<1>(k)), std::tuple<char, char>(std::get<2>(k), std::get<3>(k)));
    std::cout << "After :" << std::endl;
    print_board(j->data().board);
    j->insert(current_node);

//"j" is a node in a tree class
//"k" is structured like this: std::vector<std::tuple<char, char, char, char>>
//"MoveTo" moves a chess piece to a location on the chess board

这会产生如下输出:

Before :
 R  N  B  Q  K  B  N  R
 P  P  P  P  P  P  P  P
                        



 p  p  p  p  p  p  p  p
 R  N  B  Q  K  B  N  R
After :
 R  N  B  Q  K  B  N  R
 P  P  P  P  P  P  P  P
                        


 p
    p  p  p  p  p  p  p
 R  N  B  Q  K  B  N  R

如您所见,即使我更改了新的“ChessBoard”,“j->data()”的值也会发生变化,因此“j->data()”和新棋盘指向相同的位置在记忆中。

ChessBoard 和 Piece 的拷贝构造函数如下:

//board.h
ChessBoard(const ChessBoard& rhs) { //Copy constructor
        //This is the section that I'm concerned about ↓ (Until the other comment)
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                Piece* piece = new Piece(rhs.squares[x][y]->colour);
                piece->value = rhs.squares[x][y]->value;
                piece->symbol = rhs.squares[x][y]->symbol;
                piece->pieceType = rhs.squares[x][y]->pieceType;
                piece->moveCount = rhs.squares[x][y]->moveCount;
                ChessBoard::squares[x][y] = piece;
            }
        }
        //This is the section that I'm concerned about ↑ (Until the other comment)
        for (auto itr = rhs.promotedQueens.begin(); itr != promotedQueens.end(); ++itr) {
            Piece piece = **(itr);
            promotedQueens.push_back(&piece);
        }
        whiteCastled = rhs.whiteCastled;
        blackCastled = rhs.blackCastled;
        plyCount = rhs.plyCount;
        allowIllegalMoves = rhs.allowIllegalMoves;
        improvedDrawDetection = rhs.improvedDrawDetection;
        ChessBoard::transpos_table.initializeHash(this, Colour::White);
        initializeOriginalSquares();
    }

//Pieces.h
Piece(const Piece& rhs) { //Copy constructor
        value = rhs.value;
        symbol = rhs.symbol;
        pieceType = rhs.pieceType;
        moveCount = rhs.moveCount;
        colour = rhs.colour;
    };

总而言之,我如何制作复制构造函数来制作 ChessBoard 的深层副本 class 或以其他方式创建它的深层副本?

您正在为您的片段使用运行时多态性。 IE。你有一个指向 Piece 的棋盘,它可以是不同类型的(HorseBishop 等等)。你的问题是,当你复制构造你的棋盘时,你需要复制构造每一块,但你只持有一个 Piece* 到一个多态对象。你需要一个virtual copy constructor。根据 link 中的建议,您可以:

  • 向您的 Piece 基础 class 添加一个纯虚拟 clone 方法,并且
  • 为每个最终 classes 覆盖该方法,在那里进行复制构造。

下面的代码使用智能指针而不是原始指针。注意 *this 被传递给 std::make_unique 以调用复制构造函数。如果您什么都不传递,您将调用默认构造函数。这同样适用于使用原始指针和 new.

[Demo]

class Piece {
public:
    virtual std::unique_ptr<Piece> clone() = 0;
};

class Horse : public Piece {
public:
    virtual std::unique_ptr<Piece> clone() override {
        return std::make_unique<Horse>(*this);
    };
};

ChessBoard(const ChessBoard& cb) {
    for (size_t x{0}; x < board_size; ++x) {
        for (size_t y{0}; y < board_size; ++y) {
            squares[x][y] = cb.squares[x][y]->clone();
        }
    }
}

一些其他相关的 links:关于 virtual copy constructors. And two useful answers to that question, 1, and 2 的另一个问题。