【问题标题】:swapping vector element with a pointer from one derived class to another将向量元素与一个派生类的指针交换到另一个派生类
【发布时间】:2012-03-21 20:17:30
【问题描述】:

我有一个国际象棋游戏,最初使用 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 对象的大小比被提升为的 Knight 或 Queen 大 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() 会导致它在 new 运算符中崩溃。无论如何,我认为这仍然与我对向量 stl 的工作原理缺乏完全了解有关。我知道它与我的 Pawn() 构造函数无关,因为它在游戏板初始化期间被调用了很多次。

【问题讨论】:

  • 看起来像内存错误。如果您使用的是 Linux 或 OS X,我建议您使用 valgrind 来根除任何动态内存访问问题:valgrind.org
  • 只有这两种方法正在运行?
  • 请将您的程序缩减为显示错误的最短完整程序,并在您的问题中发布该完整程序。请参阅sscce.org 了解更多信息。
  • 好的,抱歉,感谢您的链接。我将努力减少代码然后重现错误。这是个好建议,我可能会在我这样做之后解决它:)

标签: c++ pointers stl vector polymorphism


【解决方案1】:

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

你违反了Rule of Three

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

  • 永远不要复制 ChessGame 对象。
  • 通过以下方式强制执行上述操作:
    • (C++11 之前版本):声明而不定义复制构造函数和复制赋值运算符。
    • (C++11):在复制构造函数和复制赋值运算符声明之后指定= delete
  • 将您的指针更改为智能指针(如std::shared_ptr)。或
  • 在复制构造函数和复制赋值运算符中实现深层复制。

【讨论】:

  • 我实际上从来没有在我的代码中复制 ChessGame 类,所以我认为这不是问题所在,我只通过指针或引用将它传递给方法或函数。
  • 我想我主要是在问上面的代码在我如何尝试使用向量方面看起来是否合法,并且根据反馈我猜我发布的内容看起来不错,这意味着我需要试着去别处看看。我现在最大的问题是试图弄清楚如何去调试一个在“新”中中断的错误:(如果我的内存超出范围并导致现有的连续分配被踩到它会很难知道在哪里设置断点。如果我有线程,那将是一回事,但我没有。
  • 我将像 Rob 所说的那样减少代码,然后稍后重新发布我的发现。谢谢大家,感谢所有帮助!
  • 祝你好运,@RyanVanDyke - 我可以建议调试内存损坏的两种技术是:1)Linux 上的 valgrind(或 Windows 上的一些类似产品),以及 2)测试用例减少(也称为弯刀调试) .) 如果你得到一个简短而完整的程序失败了,并且你不明白为什么,请随时提出一个新问题。
  • 我也想到,您可能会尝试审核您对newdelete 的使用。看看你能否证明这些断言:对于每个new恰好有一个delete;对于每个new[]恰好有一个delete[]。如果您的代码路径太复杂而无法证明该断言,请尝试简化您的代码或使用std::shared_ptr 而不是原始指针。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 2021-04-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多