何时调用析构函数?

时间:2018-11-03 21:12:32

标签: c++ pointers constructor copy destructor

我正在尝试创建一个函数来复制具有指针成员的类,因此指针指向的是副本而不是原始副本。在某些特定情况下,我不希望更改保留到原始版本中。

问题是在删除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());
}

析构函数:

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运行,并将指针设置回{{1} }。除非我的理解是错误的,否则很可能是这样。

1 个答案:

答案 0 :(得分:1)

我建议您为BoardState类定义一个合适的copy constructor,而不要使用Copy函数。

我假设在update t set diff = datediff(day1, day2); 行上,SimulationBoard通过值传递给PathFinder的构造函数。 PathFinder pf(simulatedBoard)的结果将使用SimulationBoard副本的析构函数。

由于SimulationBoard具有pf(simulatedBoard),因此其副本也将具有此标志,因此将为copy = truedeletep1指针调用p2。 请注意,在复制函数中也发生了同样的事情(析构函数将从walls参数中调用)。在为BoardState定义副本构造函数之前,请勿按值传递它,因为生成的副本将带有“ copy = true”标志。