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.
basic_string(const basic_string& str, size_type pos, size_type n = npos)
shouldn't use Allocator()
Section: 27.4.3.3 [string.cons] Status: NAD Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2023-08-06
Priority: 3
View all other issues in [string.cons].
View all issues with NAD status.
Discussion:
27.4.3.3 [string.cons] p3 specifies:
basic_string(const basic_string& str, size_type pos, size_type n = npos, const Allocator& a = Allocator());But this implies that
27.4.3.2 [string.require] p3 says "Thebasic_string(str, pos)
andbasic_string(str, pos, n)
useAllocator()
instead of getting an allocator fromstr
.Allocator
object used shall be obtained as described in 23.2.1." 23.2.2 [container.requirements.general] p8 says "Copy constructors for these container types obtain an allocator by callingallocator_traits<allocator_type>::select_on_container_copy_construction
on the allocator belonging to the container being copied.", but this isn't exactly a copy constructor. Then it talks about move constructors (which this definitely isn't), and finally says that "All other constructors for these container types take aconst allocator_type&
argument. […] A copy of this allocator is used for any memory allocation performed".
[2015-05-06 Lenexa: move to Open]
STL: there an allocator right there in str, why default-construct one
STL: my fix, which may not be right, splits out functions with and without allocators
JW: there are other ways to propagate the allocator from str to the new object
PJP: hard to get motivated about this one
JW: I think this is not a copy operation, this is init'ing a string from a range of characters which happens to originate in a string. It makes it inconsistent with the similar ctor taking a const char pointer, and if we had a std::string_view we wouldn't even have this ctor, and it wouldn't be possible to propagate the allocator.
STL: but people with stateful allocators want it to propagate
JW: I think the people using stateful allocators will alter the default behaviour of select_on_container_copy_construction so that it doesn't propagate, but will return a default-constructed one (to ensure a stateful allocator referring to a stack buffer doesn't leak to a region where the stack buffer has gone). So for those people, your proposed change does nothing, it changes one default-constructed allocator to a call to select_on_container_copy_construction which returns a default-constructed allocator. For other people who have different stateful allocators they can still provide the right allocator (whatever that may be) by passing it in.
STL: OK, that's convincing.
PJP: I agree with Jonathan
JW: would like to run both our arguments by Pablo in case I'm totally misrepresenting the expected users of allocator-traits stuff
[2015-10, Kona Saturday afternoon]
Everyone thinks this seems right.
STL: It'd be really weird if you copy from a string with a stateful allocator and you'd just default-construct a new allocator.
EF: We definitely need this for polymorphic allocators.
TK: Whether you think this is kind of copy-constructor or a constructor from raw string data, the new form in the PR is more flexible. You can still get the default-constructed allocator if you want, but conversely, getting the select_on_container_copy is really hard to type in the old form.
JW has objections (written in the issue) but won't block "Review" status.
Move to Review, hopefully to be made ready at a telecon.
[2015-11-22, Pablo comments]
I like the direction of the PR, but it is incomplete. Consider the following (assuming the PR):
typedef basic_string<char, char_traits<char>, A<char>> stringA; vector<stringA, scoped_allocator_adaptor<A<stringA>>> vs; stringA s; vs.emplace_back(s, 2); // Ill-formed
The problem is that uses-allocator construction requires that we be able to pass an allocator to the constructor
stringA(s, 2, allocator)
, but no such constructor exists. I think this defect already exists, but we should
fix it a the same time that we fix 2402. So, I would say we need a third constructor:
basic_string(const basic_string& str, size_type pos, const Allocator& a);
[2016-01-05, Pablo comments]
I've reconsidered and I think that the issue as stated, is NAD. I do not like the PR at all. In fact, I think it reverses a previous fix and it could break existing code.
There are two patterns that are at work here:Every constructor needs a version with and without an allocator argument (possibly through the use of default arguments).
Every constructor except the copy constructor for which an allocator is not provided uses a default-constructed allocator.
The constructors in question are not copy constructors. I do not think it is compelling that the allocator should come from its argument any more than it should come from any other object that happens to supply characters for a string constructor.
[2016-03 Jacksonville]
Closed as NAD, noting that 2583(i) is a related issue.
[2023-08-5; Arthur O'Dwyer comments]
P2438 added a constructor from basic_string&&
which also default-constructs the allocator.
JW's second argument above ("[the] proposed change does nothing") does not apply after P2438, but his first
("this is not a copy operation") is unchanged.
Previous resolution [SUPERSEDED]:
This wording is relative to N3936.
Change 27.4.3 [basic.string] p5, class template
basic_string
synopsis, as indicated:[…] // 21.4.2, construct/copy/destroy: […] basic_string(basic_string&& str) noexcept; basic_string(const basic_string& str, size_type pos, size_type n = npos); basic_string(const basic_string& str, size_type pos, size_type n= npos, const Allocator& a= Allocator()); […]Change 27.4.3.3 [string.cons] around p3 as indicated:
basic_string(const basic_string& str, size_type pos, size_type n = npos); basic_string(const basic_string& str, size_type pos, size_type n= npos, const Allocator& a= Allocator());[…]
-5- Effects: Constructs an object of classbasic_string
and determines the effective lengthrlen
of the initial string value as the smaller ofn
andstr.size() - pos
, as indicated in Table 65. The first constructor obtains an allocator by callingallocator_traits<allocator_type>::select_on_container_copy_construction
on the allocator belonging tostr
. Table 65 —basic_string(const basic_string&, size_type, size_type)
andbasic_string(const basic_string&, size_type, size_type, const Allocator&)
effects
Proposed resolution:
The existing wording is intended.