Title
Muddled allocator requirements for match_results constructors
Status
c++20
Section
[re.results.const] [re.results.all]
Submitter
Pete Becker

Created on 2012-08-29.00:00:00 last changed 37 months ago

Messages

Date: 2018-11-12.04:39:29

Proposed resolution:

This wording is relative to N4750.

  1. Edit [re.results.const] as indicated:

    -1- In all match_results constructors, a copy of the Allocator argument shall be used for any memory allocation performed by the constructor or member functions during the lifetime of the object.

Date: 2018-11-12.04:39:29

[ 2018-11, Adopted in San Diego ]

Date: 2018-06-06.21:13:21

[ 2018-06, Rapperswil ]

The group agrees with the provided resolution. Move to Ready.

Date: 2018-06-15.00:00:00

[ 2018-06-02, Daniel comments and provides wording ]

The introductory wording of match_results says in [re.results] p2:

The class template match_results satisfies the requirements of an allocator-aware container and of a sequence container (26.2.1, 26.2.3) except that only operations defined for const-qualified sequence containers are supported and that the semantics of comparison functions are different from those required for a container.

This wording essentially brings us to [container.requirements.general] which describes in p8 in general the usage of allocators:

[…] Copy constructors for these container types obtain an allocator by calling allocator_traits<allocator_ type>::select_on_container_copy_construction on the allocator belonging to the container being copied. Move constructors obtain an allocator by move construction from the allocator belonging to the container being moved. […]

The constructors referred to in the issue discussion are the copy constructor and move constructor of match_results, so we know already what the required effects are supposed to be.

[container.requirements.general] p8 also says more to this allocator topic a bit latter:

[…] All other constructors for these container types take a const allocator_type& argument. [Note: If an invocation of a constructor uses the default value of an optional allocator argument, then the Allocator type must support value-initialization. — end note] A copy of this allocator is used for any memory allocation and element construction performed, by these constructors and by all member functions, during the lifetime of each container object or until the allocator is replaced. […]

Further requirements imposed on two of the three match_results constructors can be derived from Table 80 — "Allocator-aware container requirements" via the specified expressions

X()
X(m)
X(rv)

In other words: The existing wording does already say everything that it said by [re.results.const] p1 (end even more), except for possibly the tiny problem that

match_results(const Allocator& a = Allocator());

uses "const Allocator&" instead of "const allocator_type&" in the signature, albeit even that deviation shouldn't change the intended outcome, which is IMO crystal-clear when looking at sub-clauses [container.requirements.general] and [sequence.reqmts] as a whole.

That directly makes two mutually exclusive solutions feasible:

  • Either strike [re.results.const] p1 completely; or

  • Replace [re.results.const] p1 by referring to the specification of allocators in [container.requirements.general] and [sequence.reqmts].

My suggestion is to favour for the first option, because attempting to provide extra wording that refers to allocators and the three constructors may lead to the false impression that no further allocator-related requirements hold for type match_results which are not explicitly repeated here again.

Date: 2012-08-29.00:00:00

[re.results.const] p1 says:

In all match_results constructors, a copy of the Allocator argument shall be used for any memory allocation performed by the constructor or member functions during the lifetime of the object.

There are three constructors:

match_results(const Allocator& = Allocator());
match_results(const match_results& m);
match_results(match_results&& m) noexcept;

The second and third constructors do no have an Allocator argument, so despite the "all match_results constructors", it is not possible to use "the Allocator argument" for the second and third constructors.

The requirements for those two constructors also does not give any guidance. The second constructor has no language about allocators, and the third states that the stored Allocator value is move constructed from m.get_allocator(), but doesn't require using that allocator to allocate memory.

The same basic problem recurs in [re.results.all], which gives the required return value for get_allocator():

Returns: A copy of the Allocator that was passed to the object's constructor or, if that allocator has been replaced, a copy of the most recent replacement.

Again, the second and third constructors do not take an Allocator, so there is nothing that meets this requirement when those constructors are used.

History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2018-11-12 04:39:29adminsetmessages: + msg10176
2018-11-12 04:39:29adminsetstatus: voting -> wp
2018-10-08 05:13:59adminsetstatus: ready -> voting
2018-06-06 21:13:21adminsetmessages: + msg9867
2018-06-06 21:13:21adminsetstatus: new -> ready
2018-06-02 17:04:31adminsetmessages: + msg9860
2018-06-02 17:04:31adminsetmessages: + msg9859
2012-08-29 00:00:00admincreate