Когда вызываются деструкторы? - PullRequest
0 голосов
/ 04 ноября 2018

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

Проблема возникает, когда деструктор вызывается до удаления объекта BoardState. Поэтому, когда функция Copy вызывается снова, она пытается удалить указатели и не может этого сделать, потому что они уже были удалены.

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

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

Функция копирования:

void BoardState::Copy(BoardState state)
{
    copy = true;

    if (p1 != nullptr) {
        delete p1;
    }
    p1 = new Pawn(state.getP1());

    if (p2 != nullptr) {
        delete p2;
    }
    p2 = new Pawn(state.getP2());

    if (walls != nullptr) {
        delete walls;
    }
    walls = new list<Wall>(state.getWalls());
}

Destructor:

BoardState::~BoardState()
{
    if (copy) {
        if (p1 != nullptr) {
            delete p1;
        }
        if (p2 != nullptr) {
            delete p2;
        }
        if (walls != nullptr) {
            delete walls;
        }
    }
}

В конце этой функции вызывается деструктор для SimulatedBoard:

bool AI::startThinking(Pawn& pawn, Board& board)
{
    simulatedBoard.Copy(board.getBoardState());
    allPossibleDecision.clear();
    plan.clear();
    WallOptions.clear();

    if (!thinking) {
        thinking = true;
    }

    PathFinder pf(simulatedBoard);
    list<sf::Vector2f> path = pf.createPath(board.getPawn(m_turnPos)->getPawn().getPosition(), sf::Vector2f(0, m_goal));

    int opponent_turnPos = 1;
    if (m_turnPos == 1) {
        opponent_turnPos = 2;
    }

    int opponent_goal = 160;
    if (m_goal == 160) {
        opponent_goal = 640;
    }
    list<sf::Vector2f> opponent_path = pf.createPath(board.getPawn(opponent_turnPos)->getPawn().getPosition(), sf::Vector2f(0, opponent_goal));

    int difference = opponent_path.size() - path.size();

    int i;
    if (difference < 0 && totalWalls > 0) {
        i = 1;
    }
    else {
        i = 2;
    }

    switch (i) {
    case 1: {
        list<decision>::iterator nextMove;
        Wall placeWall;
        bool foundBetterDifference = false;

        addWallOptions(sf::Vector2f(190, 190),
            simulatedBoard.getPawn(m_turnPos).getPawn().getPosition(),
            simulatedBoard.getPawn(opponent_turnPos).getPawn().getPosition());

        for (list<decision>::iterator it = allPossibleDecision.begin(); it != allPossibleDecision.end(); it++) {
            decision d = (*it);
            Wall w(d.wallPlacement, wallColor);
            if (d.rotateWall) {
                w.Rotate();
            }

            simulatedBoard.addWall(w);
            opponent_path = pf.createPath(board.getPawn(opponent_turnPos)->getPawn().getPosition(), sf::Vector2f(0, opponent_goal));
            path = pf.createPath(board.getPawn(m_turnPos)->getPawn().getPosition(), sf::Vector2f(0, m_goal));
            simulatedBoard.removeWall(w);

            int newDifference = opponent_path.size() - path.size();
            if (newDifference > difference) {
                foundBetterDifference = true;
                difference = newDifference;
                nextMove = it;
                placeWall = w;
            }
        }

        if (foundBetterDifference) {
            board.addWall(placeWall);
            plan.push_back(*nextMove);
            totalWalls--;
            break;
        }
    }
    case 2 : 
        decision d;
        d.movePawn = true;
        d.pawnPos = path.front();
        plan.push_back(d);
        board.getPawn(m_turnPos)->getPawn().setPosition(path.front());
    }

    return false;
}

SimulatedBoard не создается внутри этой функции. Это член класса. Даже если класс выходит из области видимости и это то, что удаляет SimulatedBoard, в следующий раз, когда класс снова окажется в области видимости, конструктор должен запустить для SimulatedBoard и установить указатели обратно на nullptr. Если мое понимание неверно, что вполне может быть.

1 Ответ

0 голосов
/ 04 ноября 2018

Я бы порекомендовал вам определить правильный конструктор копирования для вашего класса BoardState вместо использования функции Copy.

Я полагаю, что в строке PathFinder pf(simulatedBoard) simulatedBoard по значению передается конструктору PathFinder. Результат pf(simulatedBoard) будет использовать деструктор копии имитированной доски.

Так как simulatedBoard имеет copy = true, его копия также будет иметь этот флаг, поэтому delete будет вызываться для p1, p2 и walls указателей. Обратите внимание, что то же самое происходит в функции Copy (деструктор будет вызываться из аргумента state). Пока вы не определите конструктор копирования для BoardState, вы не должны передавать его по значению, потому что результирующая копия будет иметь флаг `copy = true '.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...