Unlike STL and std::basic_string, why there is no default allocator for std::function

Viewed 147

Unlike STL and std::basic_string, there is no default allocator for std::function. Why?

There is no default allocator for std::function in C++11. But this article(https://docs.microsoft.com/en-us/cpp/standard-library/allocators?view=msvc-160) holds the opposite opinion, which says that:

In C++11 all the Standard Library types and functions that take an allocator type parameter support the minimal allocator interface, including std::function, shared_ptr, allocate_shared(), and basic_string.

template< class Alloc >
function( std::allocator_arg_t, const Alloc& alloc,
              std::nullptr_t ) noexcept;

template<
    class CharT,
    class Traits = std::char_traits<CharT>,
    class Allocator = std::allocator<CharT>
> class basic_string;

template<class T,
class Allocator = std::allocator<T>
> class vector;
2 Answers

In C++11 and later, the most commonly used non-default constructor is this one:

template<class F> function(F);

I'm going to ignore the others for this discussion because they are less interesting but the same information applies to them.

In C++11 and C++14 it also has this, which was removed in C++20:

template<class F, class Alloc> function(std::allocator_arg_t, const Alloc&, F);

Your question is why it does not have this instead of the above constructor in C++11 and C++14:

template<class F, class Alloc> function(F, const Alloc& = Alloc());

The answer is that there is no way to invoke such a constructor using the default argument, because function(f) always calls the first constructor, and C++ does not have a way to specify the Alloc template parameter. For more on that limitation of C++, see here: Can the template parameters of a constructor be explicitly specified?

Many other types like std::vector are different because their allocator template parameter is on the overall class type, not merely on its constructor.

I assume that you are aware that allocator support in std::function was removed in C++17, so my answer will cover C++11 and C++14, with the caveat that:

std::function's allocator support was poorly specified and inconsistently implemented. Some implementations [did] not provide overloads (6-10) at all, some provide[d] the overloads but ignore[d] the supplied allocator argument, and some provide[d] the overloads and use[d] the supplied allocator for construction but not when the std::function [was] reassigned.

In C++11 and C++14, std::function did not have an allocator template parameter because it was not needed. All the members that would invoke an allocator also accepted an allocator as a function (constructor) template argument; and since std::function performs type erasure on the wrapped callable object, also performing type erasure on an allocator would be straightforward.

In the Microsoft documentation (my emphasis):

In C++11 all the Standard Library types and functions that take an allocator type parameter support the minimal allocator interface, including std::function, [...]

This is referring to the constructors of std::function taking allocator arguments (removed in C++17), which are functions taking an allocator; a constructor is a function in this context.

Related