2016-07-19 2 views
2

Я испытываю некоторое «странное поведение» при заполнении векторного значения с помощью конструктора.C++ Нечетное поведение с вектором, заполненным конструктором

Итак, у меня есть этот класс блоков, который заполняет этот статический вектор, называемый blockList, всякий раз, когда вызывается конструктор.

static std::vector<Block*> blockList; 

Block::Block(float x, float y) 
    : RectangleShape(sf::Vector2f(WIDTH, HEIGHT)) { 
    blockList.push_back(this); 
    setFillColor(sf::Color(221, 221, 221, 255)); 
    setPosition(x, y); 
} 

Теперь, когда я заполняю значения в другом классе, я назвал «Игра»; в своем конструкторе:

Game::Game(sf::RenderWindow& window) { 
    // other code here 

    Block firstBlock(10, 10); 
    // possible more blocks here 
} 

, а затем попытаться нарисовать, он разбился. Кроме того, координаты этого блока печатаются как (x: 9.8439e-12, y: 9.84394e-12). Теперь то, что я пытался делать бросает его в методе Draw (который я знаю плохо, как это постоянно называют, но для целей отладки):

void Game::drawObjects() { 
    // draw other shapes here 

    Block oneBlock(50.0f, 50.0f); 

    std::cout << std::string(10, '-') << std::endl; 
    for (Block* block : Block::getBlockList()) { 
     std::cout << block->getPosition().x << " - " << block->getPosition().y << std::endl; 
     window->draw(*block); 
    } 
    std::cout << std::string(10, '-') << std::endl; 
} 

координат и рисунок работы объекта отлично (даже если вектор сильно заселен). Поэтому мне интересно, почему это происходит, и о возможном способе обойти это. Мне не нравится эта идея, но, возможно, у меня должен быть флаг, чтобы определить, были ли они созданы, а затем создать их в методе рисования?

+0

Вы случайно не прочитали предупреждения компилятора? Они важны. –

+0

Кроме того, вы не показываете никакого механизма, который удаляет блоки в своем деструкторе. Прекратите быть умным и просто добавьте метод :: Add и :: Remove. –

+0

@DavidLively Нет никаких предупреждений, поскольку это кажется логической ошибкой. – Jujunol

ответ

6

Так мне интересно, почему это происходит

В Game::Game(), Block firstBlock(10, 10); означает firstBlock является локальным объектом, который будет уничтожен, когда выйти из сферы Game::Game(). Затем указатель, сохраненный на blockList.push_back(this); в blockList, становится болтающимся указателем, и доступ к нему приводит к UB.

и возможный способ обойти это.

Вам действительно нужен вектор pointer? Вы могли бы просто

static std::vector<Block> blockList; 

затем использовать его как:

Block firstBlock(10, 10); 
blockList.push_back(firstBlock); 
+1

Или они могут использовать 'std :: shared_ptr ', что может быть «лучше». Я также подозреваю, что 'Block :: ~ Block()' не удаляет указатель. Лично я сделаю 'blockList' отдельным классом с явными методами' add' и 'remove'. –

+0

@ KenY-N Если указатель необходим, тогда умные указатели будут лучше. В любом случае, сделать «blockList» отличной идеей. – songyuanyao

+1

Я поставил «лучше» в кавычки, поскольку я чувствовал себя «хуже», был бы более точным, но слишком тупым. –

1

В добавлении к songyuanyao ответ.

Вы должны немного подумать, что принадлежит тому, что в вашем приложении.

Думаю, Game может владеть всеми блоками, поэтому наличие vector<Block> blocks; внутри игры - это ИМО ОК.

Или, если есть много вещей, и вы хотите сохранить Game немного короче, вы можете ввести некоторые World обертки класса, владеющие блоки, то Game имеет среди прочего единого World world; экземпляра, который содержит blocks вектора.

Избегайте обнаженных указателей в источнике, они часто просто указывают, что вы не уверены, кому принадлежит экземпляр объекта. Наличие всего «принадлежности где-то» сделает всю память, освобождающую только вопрос о выходе из сферы действия.Например, если ваш main имеет локальный экземпляр Game game;, он будет полностью разрушен при выходе из main (освобождение также внутреннего экземпляра world с вектором всего blocks).

Затем C++ чувствует себя почти как GC, но вам не нужно бояться , когда происходит освобождение ресурсов, поскольку вы делаете это явным, выходя из определенной области.

Смежные вопросы