[英]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.