замена элемента вектора с указателем из одного производного класса в другой - PullRequest
0 голосов
/ 22 марта 2012

У меня есть игра в шахматы, в которой изначально использовался список stl для хранения шахматных фигур, которые я переключил на вектор для лучшей производительности.Я понимаю, что векторы не поддерживают полиморфизм, поэтому, чтобы обойти это, я сохраняю вектор <Unit *> вместо <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 для резервирования памяти кучи.В любом случае, я думаю, что это все-таки связано с отсутствием у меня полного понимания того, как работает вектор stl.Я знаю, что это не имеет ничего общего с моим конструктором Pawn (), так как он вызывался много раз во время инициализации игрового поля.

1 Ответ

0 голосов
/ 22 марта 2012

Я подозреваю, но не могу доказать из информации, которой вы поделились, что ваш конструктор копирования и оператор присваивания для ChessGame делают мелкую копию m_whiteArmy и m_blackArmy.(Примечание: если вы не предоставите конструктор копирования или оператор присваивания копии, компилятор предоставит их вам. Компиляторы, предоставленные компилятором, делают мелкие копии.)

Вы нарушили правило Три .

Вы можете исправить это следующим образом:

  • Никогда не копируя ChessGame объект.
  • Выполнение вышеуказанного с помощью:
    • (до C ++ 11): объявлять и не определять конструктор копирования и оператор назначения копирования.
    • (C ++ 11): указывать = delete после объявления конструктора копирования и оператора копирования.
  • Изменение указателей на интеллектуальные указатели (например, std::shared_ptr). Или
  • Реализация глубокой копии в конструкторе копирования и операторе копирования.
...