2162. allocator_traits::max_size missing noexcept

Section: 16.4.4.6 [allocator.requirements], 20.2.9.3 [allocator.traits.members], 20.2.9 [allocator.traits] Status: C++14 Submitter: Bo Persson Opened: 2012-07-03 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 C++14 status.

Discussion:

N3376 describes in 20.2.9.3 [allocator.traits.members]/7

static size_type max_size(Alloc& a);

Returns: a.max_size() if that expression is well-formed; otherwise, numeric_limits<size_type>::max().

The max_size function is supposed to call one of two functions that are both noexcept. To make this intermediate function useful for containers, it should preserve the noexcept attribute.

Proposed changes:

In 20.2.9 [allocator.traits] and 20.2.9.3 [allocator.traits.members]/7, change the function signature to

static size_type max_size(Alloc& a) noexcept;

[2012-08-05 Daniel comments]

On the first sight this does not seem like a defect of the specification, because the Allocator requirements in 16.4.4.6 [allocator.requirements] (Table 28) do not impose a no-throw requirement onto max_size(); the table just describes the fall-back implementation for max_size() if a given allocator does not provide such a function.

std::allocator as a special model of this concept and is allowed to increase the exception-guarantees for max_size(), but this does not imply a corresponding rules for other allocators.

Furthermore, max_size() of Containers is not specified in terms of Allocator::max_size(), so again this is not a real contradiction.

Nonetheless I think that the following stronger decision should be considered:

  1. Require that for all Allocators (as specified in 16.4.4.6 [allocator.requirements]) max_size() never throws an exception. This would it make much more useful to call this function in situations where no exception should leave the context.

  2. Require that for all Allocators (as specified in 16.4.4.6 [allocator.requirements]) max_size() can be called on const allocator object. Together with the previous item this would allow an implementation of a container's max_size() function to delegate to the allocator's max_size() function.

In regard to the second statement it should be mentioned that there are two current specification deviations from that in the draft:

  1. The synopsis of 20.2.9 [allocator.traits] uses a const allocator argument as part of the signature of the max_size function.

  2. Both the synopsis of 20.5.1 [allocator.adaptor.syn] and the member specification in 20.5.4 [allocator.adaptor.members] p8 declare scoped_allocator_adaptor::max_size as const member function, but this function delegates to

    allocator_traits<OuterAlloc>::max_size(outer_allocator())
    

    where outer_allocator() resolves to the member function overload returning a const outer_allocator_type&.

The question arises whether these current defects actually point to a defect in the Allocator requirements and should be fixed there.

[ 2012-10 Portland: Move to Review ]

Consensus that the change seems reasonable, and that for any given type the template is intantiated with the contract should be 'wide' so this meets the guidelines we agreed in Madrid for C++11.

Some mild concern that while we don't imagine many allocator implementations throwing on this method, it is technically permited by current code that we would not be breaking, by turning throw expressions into disguised terminate calls. In this case, an example might be an instrumented 'logging' allocator that writes every function call to a log file or database, and might throw if that connection/file were no longer available.

Another option would be to make exception spefication a conditional no-except, much like we do for some swap functions and assignment operators. However, this goes against the intent of the Madrid adoption of noexcept which is that vendors are free to add such extensions, but we look for a clear line in the library specification, and do not want to introduce conditional-noexcept piecemeal. A change in our conventions here would require a paper addressing the library specification as a whole.

Consensus was to move forward, but move the issue only to Review rather than Ready to allow time for further comments. This issue should be considered 'Ready' next time it is reviewed unless we get such comments in the meantime.

[2013-04-18, Bristol]

Proposed resolution:

In 20.2.9 [allocator.traits] and 20.2.9.3 [allocator.traits.members]/7, change the function signature to

static size_type max_size(Alloc& a) noexcept;