c++allocatornoexceptc++pmr

Can the ctor be marked noexcept based on allocator type?


How should I make sure that a constructor is noexcept if the allocator does not throw?

Here is an MRE:

#include <iostream>
#include <array>
#include <vector>
#include <memory_resource>
#include <concepts>
#include <cstddef>


template < std::unsigned_integral T, class Allocator = std::allocator<T> >
class Foo
{
    std::vector<T, Allocator> vec;

public:
    Foo( const size_t size, const T value,
         const Allocator& alloc = Allocator { } ) noexcept( noexcept( Allocator { } ) )
    : vec { size, value, alloc }
    {
    }
};

int main( )
{
    Foo<unsigned> my_foo { 10, 505 };

    auto buffer { std::array<std::byte, 50> { } };
    std::pmr::monotonic_buffer_resource rsrc { buffer.data( ), buffer.size( ) };

    Foo< unsigned, std::pmr::polymorphic_allocator<unsigned> > my_foo_pmr { 10, 505, &rsrc };


    std::cout << std::boolalpha
              << noexcept( std::pmr::polymorphic_allocator<unsigned> { } ) << '\n' // true
              << noexcept( std::allocator<unsigned> { } ) << '\n'                  // true
              << std::noboolalpha;
}

First of all, I wonder why does noexcept( std::allocator<unsigned> { } ) return true? Is std::allocator<unsigned> exception safe? Like a vector with this allocator never throws? And what about the pmr allocator that has a stack-based buffer? Can it throw?

Secondly, what is the proper way of ensuring that the above class's ctor is marked noexcept if it actually never throws?


Solution

  • First of all, I wonder why does noexcept( std::allocator<unsigned> { } ) return true?

    Because constructing a std::allocator<unsigned> does not throw.

    Secondly, what is the proper way of ensuring that the above class's ctor is marked noexcept if it actually never throws?

    The proper way is to not mark it as noexcept because it may throw. The vector constructor you are calling is not noexcept. Only std::vectors default constructor is noexcept( noexcept(Allocator()), but you are calling a different constructor. With a pmr allocator I suppose nothing is different, because when size is too big then being able to construct the allocator without exceptions does not help to avoid running out of memory once you allocate too many elements.