This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.

### 560. User-defined allocators without default constructor

Section: 16.4.4.6 [allocator.requirements] Status: NAD Submitter: Sergey P. Derevyago Opened: 2006-02-17 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

#### 1. The essence of the problem.

User-defined allocators without default constructor are not explicitly supported by the standard but they can be supported just like std::vector supports elements without default constructor.

As a result, there exist implementations that work well with such allocators and implementations that don't.

#### 2. The cause of the problem.

1) The standard doesn't explicitly state this intent but it should. In particular, 20.1.5p5 explicitly state the intent w.r.t. the allocator instances that compare non-equal. So it can similarly state the intent w.r.t. the user-defined allocators without default constructor.

2) Some container operations are obviously underspecified. In particular, 21.3.7.1p2 tells:

>     template<class charT, class traits, class Allocator>
>       basic_string<charT,traits,Allocator> operator+(
>         const charT* lhs,
>         const basic_string<charT,traits,Allocator>& rhs
>       );

> Returns: `basic_string<charT,traits,Allocator>(lhs) + rhs`.

That leads to the basic_string<charT,traits,Allocator>(lhs, Allocator()) call. Obviously, the right requirement is:

> Returns: `basic_string<charT,traits,Allocator>(lhs, rhs.get_allocator()) + rhs`.

It seems like a lot of DRs can be submitted on this "Absent call to get_allocator()" topic.

#### 3. Proposed actions.

1) Explicitly state the intent to allow for user-defined allocators without default constructor in 20.1.5 Allocator requirements.

2) Correct all the places, where a correct allocator object is available through the get_allocator() call but default Allocator() gets passed instead.

#### 4. Code sample.

Let's suppose that the following memory pool is available:

>     class mem_pool {
>           // ...
>           void* allocate(size_t size);
>           void deallocate(void* ptr, size_t size);
>     };

So the following allocator can be implemented via this pool:

>     class stl_allocator {
>           mem_pool& pool;

>      public:
>           explicit stl_allocator(mem_pool& mp) : pool(mp) {}
>           stl_allocator(const stl_allocator& sa) : pool(sa.pool) {}
>           template <class U>
>           stl_allocator(const stl_allocator<U>& sa)  : pool(sa.get_pool()) {}
>           ~stl_allocator() {}

>           pointer allocate(size_type n, std::allocator<void>::const_pointer = 0)
>           {
>            return (n!=0) ? static_cast<pointer>(pool.allocate(n*sizeof(T))) : 0;
>           }

>           void deallocate(pointer p, size_type n)
>           {
>            if (n!=0) pool.deallocate(p, n*sizeof(T));
>           }

>           // ...
>     };

Then the following code works well on some implementations and doesn't work on another:

>     typedef basic_string<char, char_traits<char>, stl_allocator<char> >
>       tl_string;
>     mem_pool mp;
>     tl_string s1("abc", stl_allocator<int>(mp));
>     printf("(%s)\n", ("def"+s1).c_str());

In particular, on some implementations the code can't be compiled without default stl_allocator() constructor.

The obvious way to solve the compile-time problems is to intentionally define a NULL pointer dereferencing default constructor

>     stl_allocator() : pool(*static_cast<mem_pool*>(0)) {}

in a hope that it will not be called. The problem is that it really gets called by operator+(const char*, const string&) under the current 21.3.7.1p2 wording.

Proposed resolution:

Rationale:

Recommend NAD. `operator+()` with `string` already requires the desired semantics of copying the allocator from one of the strings (lhs when there is a choice).