簡體   English   中英

unique_ptr的向量是什么?

[英]vector of unique_ptr deleting?

我有一個我無法弄清楚的段錯誤問題。 它來自一個EntityManager用於我正在研究的小型游戲引擎。 我可以添加Ship Entity ,並且Ship可以添加1個Bullet Entity ,但如果我嘗試添加超過1個Bullet則會發生段錯誤。 我一直試圖在過去的一天里把這個想象成現實。 以下是實際代碼的一小段摘錄。

#include <vector>
#include <memory>

struct EntityManager;
struct Entity {
    Entity(EntityManager* manager) : manager(manager) { }
    virtual ~Entity() { }
    virtual void update() = 0;

    EntityManager* manager;
};
struct EntityManager {
    void update() {
        for (auto& entity : entities) {
            entity->update();
        }
    }
    void add(Entity* e) {
        entities.emplace_back(e);
    }
    std::vector<std::unique_ptr<Entity>> entities;
};
struct Bullet : public Entity {
    Bullet(EntityManager* manager) : Entity(manager) { printf("Bullet ctor\n"); }

    virtual void update() override { }
};
struct Ship : public Entity {
    Ship(EntityManager* manager) : Entity(manager) { }

    virtual void update() override {
        printf("Adding Bullet\n");
        manager->add(new Bullet(manager));
    }
};
int main() {
    EntityManager manager;
    manager.add(new Ship(&manager));

    int loops{0};
    while (loops < 100) {
        manager.update();
        loops++;
        printf("Completed Loop #%d\n", loops);
    }
    return 0;
}

在實際的代碼中,一切都在他們自己的.h / .cpp文件中,而是在類而不是結構中,但問題是相同的。 輸出是`Adding Bullet // Bullet ctor // Completed Loop#1 //添加Bullet // Bullet ctor //信號:SIGSEGV(分段錯誤)

segfault發生在entity->update();EntityManager::update() entity->update(); 線。

問題是這個循環修改了向量:

    for (auto& entity : entities) {
        entity->update();
    }

當您修改向量以添加新元素時,您正在忙於迭代它,這會使用於遍歷容器的迭代器無效。

基於范圍的for循環由編譯器擴展為:

auto begin = entities.begin(), end = entities.end();
for (; begin != end; ++begin)
  begin->update();

begin->update()的調用會向向量添加一個新元素,這會使所有迭代器無效進入容器,因此++begin是未定義的行為。 實際上, begin不再指向向量(因為它已經重新分配並釋放了begin指向的舊內存),因此下一個begin->update()調用取消引用無效迭代器,訪問釋放的內存和seg-faulting。

為了安全地做到這一點,你可能想要使用索引而不是迭代器:

for (size_t i = 0, size = entities.size(); i != size; ++i)
  entities[i].update();

這將捕獲循環開始時的大小,因此只迭代循環開始時存在的最后一個元素,因此添加到末尾的新元素將不會被訪問。

當修改向量時,這仍然有效,因為您不存儲迭代器或指向元素的指針,只存儲索引。 只要不從向量中刪除元素,即使插入新元素,索引仍然有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM