Skip to content

Commit

Permalink
[aa_inplace_vector] Copying/moving an Alloc is not allowed to throw
Browse files Browse the repository at this point in the history
The Standard specifies in [allocator.requirements.general] that copy
and move operations on allocators never throw, regardless of whether
they're marked noexcept or not. And in fact `boost::interprocess::allocator`
does not mark its SMFs as noexcept. So we shouldn't check the trait
here; instead we should assume that the operations are non-throwing.
  • Loading branch information
Quuxplusone committed Aug 25, 2024
1 parent 81eeab1 commit 60e8aec
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
11 changes: 7 additions & 4 deletions include/sg14/aa_inplace_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ struct ipv_alloc_holder {
#endif
explicit ipv_alloc_holder() = default;
constexpr explicit ipv_alloc_holder(const Alloc& alloc) : alloc_(alloc) {}
ipv_alloc_holder(const ipv_alloc_holder&) noexcept = default;
ipv_alloc_holder(ipv_alloc_holder&&) noexcept = default;
ipv_alloc_holder& operator=(const ipv_alloc_holder&) noexcept = default;
ipv_alloc_holder& operator=(ipv_alloc_holder&&) noexcept = default;
~ipv_alloc_holder() noexcept = default;
constexpr const Alloc& get_allocator_() const { return alloc_; }
};

Expand Down Expand Up @@ -397,13 +402,11 @@ struct SG14_INPLACE_VECTOR_TRIVIALLY_RELOCATABLE_IF((sg14::aaipv::be_trivially_r
static constexpr bool CopyCtorIsNoexcept =
((std::is_nothrow_copy_constructible_v<T> &&
sg14::aaipv::has_trivial_construct<Alloc, T, const T&>::value) || (N == 0)) &&
sg14::aaipv::propagate_on_container_copy_construction<Alloc>::value &&
std::is_nothrow_copy_constructible_v<sg14::ipv_alloc_holder<Alloc>>;
sg14::aaipv::propagate_on_container_copy_construction<Alloc>::value;

static constexpr bool MoveCtorIsNoexcept =
((std::is_nothrow_move_constructible_v<T> &&
sg14::aaipv::has_trivial_construct<Alloc, T, T&&>::value) || (N == 0)) &&
std::is_nothrow_move_constructible_v<sg14::ipv_alloc_holder<Alloc>>;
sg14::aaipv::has_trivial_construct<Alloc, T, T&&>::value) || (N == 0));

// Copy-assignment follows the Lakos Rule: if the precondition might be violated, then it's not noexcept.
//
Expand Down
37 changes: 37 additions & 0 deletions test/aa_inplace_vector_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ struct CountingAlloc {
}
};

template<class T, bool B>
struct NonNoexceptAlloc {
using value_type = T;
using propagate_on_container_copy_assignment = std::bool_constant<B>;
using propagate_on_container_move_assignment = std::bool_constant<B>;
using propagate_on_container_swap = std::bool_constant<B>;
using is_always_equal = std::false_type;
explicit NonNoexceptAlloc(int);
NonNoexceptAlloc(const NonNoexceptAlloc&); // non-throwing but not noexcept
NonNoexceptAlloc(NonNoexceptAlloc&&); // non-throwing but not noexcept
NonNoexceptAlloc& operator=(const NonNoexceptAlloc&); // non-throwing but not noexcept
NonNoexceptAlloc& operator=(NonNoexceptAlloc&&); // non-throwing but not noexcept
~NonNoexceptAlloc() noexcept(false); // non-throwing but not noexcept
friend bool operator==(NonNoexceptAlloc, NonNoexceptAlloc); // non-throwing but not noexcept
int i_;
};

TEST(aa_inplace_vector, AllocExtendedCopyCtor)
{
using A = CountingAlloc<int>;
Expand Down Expand Up @@ -63,4 +80,24 @@ TEST(aa_inplace_vector, AllocExtendedMoveCtor)
EXPECT_EQ(mr2.size(), 3u);
}

TEST(aa_inplace_vector, IgnoreNoexceptnessOfAllocator)
{
{
using T = sg14::inplace_vector<int, 10, NonNoexceptAlloc<int, true>>;
static_assert(std::is_nothrow_copy_constructible_v<T>);
static_assert(std::is_nothrow_move_constructible_v<T>);
static_assert(std::is_nothrow_copy_assignable_v<T>);
static_assert(std::is_nothrow_move_assignable_v<T>);
static_assert(std::is_nothrow_destructible_v<T>);
}
{
using T = sg14::inplace_vector<int, 10, NonNoexceptAlloc<int, false>>;
static_assert(std::is_nothrow_copy_constructible_v<T>);
static_assert(std::is_nothrow_move_constructible_v<T>);
static_assert(std::is_nothrow_copy_assignable_v<T>);
static_assert(std::is_nothrow_move_assignable_v<T>);
static_assert(std::is_nothrow_destructible_v<T>);
}
}

#endif // __cplusplus >= 202002L

0 comments on commit 60e8aec

Please sign in to comment.