我有一个包含三个类的层次结构,其中 Derived
源自 Selectable
和 Drawable
.然后我有一个 std::vector
的 std::unique_ptr<Drawable>
我用 Derived
填充对象。
我确定该 vector 将仅由同时从两个基派生的对象填充。
当我尝试使用指向 Selected
的指针从 vector 中删除某个元素时,问题就来了.
#include <vector>
#include <memory>
#include <algorithm>
struct Selectable {
virtual ~Selectable() = 0;
};
Selectable::~Selectable() = default;
struct Drawable {
virtual ~Drawable() = 0;
};
Drawable::~Drawable() = default;
struct Derived : Selectable, Drawable {};
int main()
{
std::vector<std::unique_ptr<Drawable>> vec;
for (int i = 0; i < 5; ++i) {
vec.push_back(std::make_unique<Derived>());
}
Selectable* selected = dynamic_cast<Selectable*>(vec[2].get());
vec.erase(std::remove_if(vec.begin(), vec.end(),
[selected](auto&& ptr) {
return ptr.get() == dynamic_cast<Drawable*>(selected);
}), vec.end());
}
显然,如果我制作 selected
成为指向 Drawable
的指针,一切都很好,但这不是我的本意。
我收到一个导致程序崩溃的运行时错误。为什么会发生这种情况,我该如何解决?
最佳答案
关键问题在于 std::remove_if
“删除”元素的方式:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. Relative order of the elements that remain is preserved and the physical size of the container is unchanged. Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition).
所以基本上,您保留了 auto ptr = vec[2].get()
获取的原始指针,但没有人保证 ptr
仍然有效。你只能保证 vec[2]
是有效的。 (过滤前在vec[2]
中的唯一指针现在位于新的逻辑端和物理端之间,未指定值)。
在您的示例中,当 std::remove_if
到达第三个元素时,谓词返回 true
并且 remove_if
调用 vec[ 2].get()
的析构函数。
因为你保留了一个指向它的原始指针,所以你正在使用一个指向已经被销毁的对象的指针。
关于c++ - std::remove_if 来自 std::vector 的多态 std::unique_ptr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43706186/