BLI: destruct non-trivial types after using remove_if
`Vector::remove_if` allows certain elements to be removed based on a predicate. However `std::remove_if` only shifts the elements that will not be deleted to the beginning of the container and then `Vector::remove_if` only updates the pointer to the new last element after using `std::remove_if`. This works well if `Vector` is used with trivial types that don't have a destructor. Having a `Vector<std::unique_ptr>` for example, can generate undefined behavior if the predicate gives `true` to elements that are contiguous at the end, if `Vector::remove_if` only updates the end pointer in these specific cases, these makes these smart pointers useless because they will not be freed by themselves. To prevent that, also destruct the elements being removed. Pull Request: https://projects.blender.org/blender/blender/pulls/115914
This commit is contained in:
parent
efc1094d6a
commit
e23b8eeb42
|
@ -816,6 +816,7 @@ class Vector {
|
|||
{
|
||||
const T *prev_end = this->end();
|
||||
end_ = std::remove_if(this->begin(), this->end(), predicate);
|
||||
destruct_n(end_, prev_end - end_);
|
||||
UPDATE_VECTOR_SIZE(this);
|
||||
return int64_t(prev_end - end_);
|
||||
}
|
||||
|
|
|
@ -431,6 +431,17 @@ TEST(vector, RemoveIf)
|
|||
EXPECT_EQ_ARRAY(vec.data(), expected_vec.data(), size_t(vec.size()));
|
||||
}
|
||||
|
||||
TEST(vector, RemoveIfNonTrivialDestructible)
|
||||
{
|
||||
Vector<Vector<int, 0, GuardedAllocator>> vec;
|
||||
for ([[maybe_unused]] const int64_t i : IndexRange(10)) {
|
||||
/* This test relies on leak detection to run after tests. */
|
||||
vec.append(Vector<int, 0, GuardedAllocator>(100));
|
||||
}
|
||||
vec.remove_if([&](const auto & /*value*/) { return true; });
|
||||
EXPECT_TRUE(vec.is_empty());
|
||||
}
|
||||
|
||||
TEST(vector, ExtendSmallVector)
|
||||
{
|
||||
Vector<int> a = {2, 3, 4};
|
||||
|
|
Loading…
Reference in New Issue