将具有指针的向量元素从一个派生类交换到另一派生类

swapping vector element with a pointer from one derived class to another

本文关键字:派生 一个 交换 指针 向量 元素      更新时间:2023-10-16

我有一个国际象棋游戏,最初使用stl列表来存储棋子,为了获得更好的性能,我将其转换为向量。我知道载体不支持多态性,所以为了解决这个问题,我存储了一个<Unit *>的载体,而不是<Unit>。我所有的棋子对象(Pawn、Rook、Bishop等)都继承自Unit类。

然而,向量和堆损坏似乎仍然存在问题。我想我已经追踪到以下功能:

Unit *ChessGame::PromoteUnit(Unit *_oldUnit, UnitType _newType)
{
vector<Unit *> &army = (_oldUnit->m_gameColor == WHITE) ? m_whiteArmy : m_blackArmy;
Unit *newUnit = NULL;
for (unsigned int i = 0; i < army.size(); ++i)
{
    if (army[i]->m_subId == _oldUnit->m_subId)
    {
        if (_newType == QUEEN && _oldUnit->m_gameColor == WHITE)
        {
            newUnit = new Queen(*_oldUnit);
            newUnit->ActiveTexture_(m_textureMan->TextureId_(WhiteQueen));
        }
        else if (_newType == KNIGHT && _oldUnit->m_gameColor == WHITE)
        {
            newUnit = new Knight(*_oldUnit);
            newUnit->ActiveTexture_(m_textureMan->TextureId_(WhiteKnight));
        }
        else if (_newType == QUEEN && _oldUnit->m_gameColor == BLACK)
        {
            newUnit = new Queen(*_oldUnit);
            newUnit->ActiveTexture_(m_textureMan->TextureId_(BlackQueen));
        }
        else if (_newType == KNIGHT && _oldUnit->m_gameColor == BLACK)
        {
            newUnit = new Knight(*_oldUnit);
            newUnit->ActiveTexture_(m_textureMan->TextureId_(BlackKnight));
        }
        newUnit->m_wasPawn = true;
        delete army[i];
        army[i] = newUnit;
        break;
    }
}
m_selectedUnit = newUnit;
return newUnit;
}

既然一个指针无论指向什么都只有4个字节,那么在这种情况下,stl向量仍然会有问题是有原因的吗?我的Pawn对象比被提升为骑士或王后的对象大8个字节,这也许可以解释我一直以来出现的奇怪的内存错误。当我备份我的回合历史并点击降级功能来逆转升级时:

Unit *ChessGame::DemoteUnit(Unit *_oldUnit, UnitType _newType)
{
COUT("ChessGameManager::_DemoteUnit(Unit *, UnitType)");
vector<Unit *> &army = (_oldUnit->m_gameColor == WHITE) ? m_whiteArmy : m_blackArmy;
Unit *newUnit = NULL;
for (unsigned int i = 0; i < army.size(); ++i)
{
    if (army[i]->m_subId == _oldUnit->m_subId)
    {
        newUnit = new Pawn();
        newUnit->m_wasPawn = false;
        if (_oldUnit->m_gameColor == WHITE)
            newUnit->ActiveTexture_(m_textureMan->TextureId_(WhitePawn));
        newUnit->m_gameColor = _oldUnit->m_gameColor;
        newUnit->MobilityValid_(false);
        newUnit->Color_(RvColor::ClrWhite);
        newUnit->m_square = _oldUnit->m_square;
        newUnit->m_captured = false;
        newUnit->m_origin = _oldUnit->m_origin;
        newUnit->m_subId = _oldUnit->m_subId;
        newUnit->m_visible = true;
        //newUnit->m_square->m_unit = newUnit;
        delete army[i];
        army[i] = newUnit;
        break;
    }
}
return newUnit;
}

它真的崩溃了:

newUnit = new Pawn();

当它试图使用malloc来保留堆内存时,进入new Pawn()会导致它在新操作符内崩溃。无论如何,我认为这仍然与我对向量stl的工作原理缺乏完全理解有关。我知道它与我的Pawn()构造函数无关,因为它在游戏板初始化期间被调用了很多次。

我怀疑,但无法从您共享的信息中证明,ChessGame的复制构造函数和复制赋值运算符正在执行m_whiteArmym_blackArmy的浅层复制。(注意:如果你没有提供复制构造函数或复制赋值运算符,编译器会为你提供它们。编译器提供的是浅层复制。)

你违反了三条规则。

您可以通过以下方式解决此问题:

  • 从不复制ChessGame对象
  • 通过以下方式执行上述规定:
    • (C++11之前):声明和不定义复制构造函数和复制赋值运算符
    • (C++11):在复制构造函数和复制赋值运算符声明之后指定= delete
  • 将指针更改为智能指针(如std::shared_ptr)。,或
  • 在复制构造函数和复制赋值运算符中实现深度复制
相关文章: