如何在矢量中添加和删除对象<unique_ptr>...?



我有两个这样的函数。当我添加一个新对象时,一切正常,但如果我试图添加一个已经在这个向量中的对象,应用程序就会关闭。我正在运行unique_ptr析构函数后,从一个矢量删除。如何解决这个问题?

void AddObject(GameObject* obj) {
objects().push_back(std::move(unique_ptr<GameObject>(obj)));
}

void DeleteObject(GameObject* obj) {
for (auto itr = objects().begin(); itr != objects().end(); ++itr) {
if ((*itr)->ID == obj->ID) {
objects().erase(std::move(itr));
itr->~unique_ptr();
}
}
}

你所展示的代码都是错误的。

AddObject()应采用unique_ptr<GameObject>作为输入,而不是原始的GameObject*指针,例如:

void AddObject(unique_ptr<GameObject> obj) {
objects().push_back(std::move(obj));
}

否则,调用者可能会多次添加同一个对象,因此它将由多个unique_ptr管理。

一个更好的选择是不让调用者开始创建自己的对象。让调用者指定对象类型和构造函数参数,但让AddObject()处理实际创建,例如:

template<typename T, typename... Args>
void AddObject(Args&&... args) {
objects().push_back(std::make_unique<T>(std::forward<Args>(args)...));
}

对于DeleteObject(),erase()从vector中获取元素会使指向擦除点()后的元素的迭代器失效,包括被擦除的迭代器。你的循环没有考虑到这一点。erase()返回一个迭代器到被擦除的元素之后的元素,所以如果你不打算在循环中使用break(你可以有多个具有相同ID值的对象吗?),那么你需要使用iterator来正确地继续循环。

同样,直接调用不是用placement-new创建的对象的析构函数是未定义行为。在这种情况下,根本没有理由手动销毁unique_ptr。当它们从vector中移出作用域时,它们将自动被销毁。

如果你想让DeleteObject()搜索一个特定的对象,那么它应该寻找那个特定的对象指针,而不是一个ID:

void DeleteObject(GameObject* obj) {
auto &objs = objects();
for (auto itr = objs.begin(); itr != objs.end(); ++itr) {
if (itr->get() == obj) {
objs.erase(itr);
return;
}
}
}

另外:

void DeleteObject(GameObject* obj) {
auto &objs = objects();
auto itr = std::find_if(objs.begin(), objs.end(),
[=](auto &ptr){ return ptr.get() == obj; }
);
if (itr != objs.end()) {
objs.erase(itr);
}
}

如果你想让DeleteObject()搜索一个ID,那么它应该接受一个ID作为输入,而不是一个对象指针:

void DeleteObject(int ID) {
auto &objs = objects();
for (auto itr = objs.begin(); itr != objs.end(); ++itr) {
if ((*itr)->ID == ID) {
itr = objs.erase(itr);
return;
}
}
}

另外:

void DeleteObject(int ID) {
auto &objs = objects();
auto itr = std::find_if(objs.begin(), objs.end(),
[=](auto &ptr){ return ptr->ID == ID; }
);
if (itr != objs.end()) {
objs.erase(itr);
}
}

,如果多个对象可以有相同的ID (?):

void DeleteObject(int ID) {
auto &objs = objects();
for (auto itr = objs.begin(); itr != objs.end(); ) {
if ((*itr)->ID == ID) {
itr = objs.erase(itr);
}
else {
++itr;
}
}
}

另外:

void DeleteObject(int ID) {
auto &objs = objects();
objs.erase(
std::remove_if(objs.begin(), objs.end(),
[=](auto &ptr){ return ptr->ID == ID; }
),
objs.end()
);
// or, in C++20 and later:
std::erase_if(objs,
[=](auto &ptr){ return ptr->ID == ID; }
);
}

相关内容

  • 没有找到相关文章

最新更新