Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions absl/container/inlined_vector_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,33 @@ TEST(UniquePtr, MoveAssign) {
}
}

// Swapping containers of unique pointers should work fine, with no
// leaks, despite the fact that unique pointers are trivially relocatable but
// not trivially destructible.
TEST(UniquePtr, Swap) {
for (size_t size1 = 0; size1 < 5; ++size1) {
for (size_t size2 = 0; size2 < 5; ++size2) {
absl::InlinedVector<std::unique_ptr<size_t>, 2> a;
absl::InlinedVector<std::unique_ptr<size_t>, 2> b;
for (size_t i = 0; i < size1; ++i) {
a.push_back(std::make_unique<size_t>(i + 10));
}
for (size_t i = 0; i < size2; ++i) {
b.push_back(std::make_unique<size_t>(i + 20));
}
a.swap(b);
ASSERT_THAT(a, SizeIs(size2));
ASSERT_THAT(b, SizeIs(size1));
for (size_t i = 0; i < a.size(); ++i) {
ASSERT_THAT(a[i], Pointee(i + 20));
}
for (size_t i = 0; i < b.size(); ++i) {
ASSERT_THAT(b[i], Pointee(i + 10));
}
}
}
}

// At the end of this test loop, the elements between [erase_begin, erase_end)
// should have reference counts == 0, and all others elements should have
// reference counts == 1.
Expand Down
15 changes: 7 additions & 8 deletions absl/container/internal/inlined_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,13 @@ class Storage {

// The policy to be used specifically when swapping inlined elements.
using SwapInlinedElementsPolicy = absl::conditional_t<
// Fast path: if the value type can be trivially move constructed/assigned
// and destroyed, and we know the allocator doesn't do anything fancy,
// then it's safe for us to simply swap the bytes in the inline storage.
// It's as if we had move-constructed a temporary vector, move-assigned
// one to the other, then move-assigned the first from the temporary.
absl::conjunction<absl::is_trivially_move_constructible<ValueType<A>>,
absl::is_trivially_move_assignable<ValueType<A>>,
absl::is_trivially_destructible<ValueType<A>>,
// Fast path: if the value type can be trivially relocated, and we
// know the allocator doesn't do anything fancy, then it's safe for us
// to simply swap the bytes in the inline storage. It's as if we had
// relocated the first vector's elements into temporary storage,
// relocated the second's elements into the (now-empty) first's,
// and then relocated from temporary storage into the second.
absl::conjunction<absl::is_trivially_relocatable<ValueType<A>>,
std::is_same<A, std::allocator<ValueType<A>>>>::value,
MemcpyPolicy,
absl::conditional_t<IsSwapOk<A>::value, ElementwiseSwapPolicy,
Expand Down