Title
allocator_traits::max_size missing noexcept
Status
c++14
Section
[allocator.requirements] [allocator.traits.members] [allocator.traits]
Submitter
Bo Persson

Created on 2012-07-03.00:00:00, last changed 2014-02-20.13:20:35.

Messages

Date: 2013-04-18.22:58:13

Proposed resolution:

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

static size_type max_size(Alloc& a) noexcept;
Date: 2013-04-15.00:00:00

[ 2013-04-18, Bristol ]

Date: 2012-10-16.15:35:12

[ 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.

Date: 2012-08-05.00:00:00

[ 2012-08-05 Daniel comments ]

On the first sight this does not seem like a defect of the specification, because the Allocator requirements in [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 [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 [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 [allocator.traits] uses a const allocator argument as part of the signature of the max_size function.

  2. Both the synopsis of [allocator.adaptor.syn] and the member specification in [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.

Date: 2012-07-03.00:00:00

N3376 describes in [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 [allocator.traits] and [allocator.traits.members]/7, change the function signature to

static size_type max_size(Alloc& a) noexcept;
History
Date User Action Args
2014-02-20 13:20:35adminsetstatus: wp -> c++14
2013-04-25 19:07:07adminsetstatus: voting -> wp
2013-04-19 21:44:50adminsetstatus: ready -> voting
2013-04-18 22:58:13adminsetmessages: + msg6457
2013-04-18 22:58:13adminsetstatus: review -> ready
2012-10-16 15:35:12adminsetmessages: + msg6174
2012-10-16 15:35:12adminsetmessages: + msg6173
2012-10-16 15:35:12adminsetstatus: new -> review
2012-08-05 16:44:00adminsetmessages: + msg6096
2012-07-03 00:00:00admincreate