<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2402: basic_string(const basic_string&amp; str, size_type pos, size_type n = npos) shouldn't use Allocator()</title>
<meta property="og:title" content="Issue 2402: basic_string(const basic_string&amp; str, size_type pos, size_type n = npos) shouldn't use Allocator()">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2402.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#NAD">NAD</a> status.</em></p>
<h3 id="2402"><a href="lwg-closed.html#2402">2402</a>. <code>basic_string(const basic_string&amp; str, size_type pos, size_type n = npos)</code> shouldn't use <code>Allocator()</code></h3>
<p><b>Section:</b> 27.4.3.3 <a href="https://wg21.link/string.cons">[string.cons]</a> <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Stephan T. Lavavej <b>Opened:</b> 2014-06-14 <b>Last modified:</b> 2023-08-06</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#string.cons">issues</a> in [string.cons].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>
<p>
27.4.3.3 <a href="https://wg21.link/string.cons">[string.cons]</a> p3 specifies:
</p>
<blockquote>
<pre>
basic_string(const basic_string&amp; str, size_type pos, size_type n = npos, const Allocator&amp; a = Allocator());
</pre>
<p>
But this implies that <code>basic_string(str, pos)</code> and <code>basic_string(str, pos, n)</code> use <code>Allocator()</code> 
instead of getting an allocator from <code>str</code>.
<p/>
27.4.3.2 <a href="https://wg21.link/string.require">[string.require]</a> p3 says "The <code>Allocator</code> object used shall be obtained as described in 23.2.1."  
23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a> p8 says "Copy constructors for these container types obtain an allocator 
by calling <code>allocator_traits&lt;allocator_type&gt;::select_on_container_copy_construction</code> 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 a 
<code>const allocator_type&amp;</code> argument. [&hellip;] A copy of this allocator is used for any memory allocation performed".
</p>
</blockquote>

<p><i>[2015-05-06 Lenexa: move to Open]</i></p>

<p>STL: there an allocator right there in str, why default-construct one</p>
<p>STL: my fix, which may not be right, splits out functions with and without allocators</p>
<p>JW: there are other ways to propagate the allocator from str to the new object</p>
<p>PJP: hard to get motivated about this one</p>
<p>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.</p>
<p>STL: but people with stateful allocators want it to propagate</p>
<p>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.</p>
<p>STL: OK, that's convincing.</p>
<p>PJP: I agree with Jonathan</p>
<p>JW: would like to run both our arguments by Pablo in case I'm totally misrepresenting the expected users of allocator-traits stuff</p>

<p><i>[2015-10, Kona Saturday afternoon]</i></p>

<p>Everyone thinks this seems right.</p>
<p>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.</p>
<p>EF: We definitely need this for polymorphic allocators.</p>
<p>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.</p>
<p>JW has objections (written in the issue) but won't block "Review" status.</p>
<p>Move to Review, hopefully to be made ready at a telecon.</p>

<p><i>[2015-11-22, Pablo comments]</i></p>

<p>
I like the direction of the PR, but it is incomplete. Consider the following (assuming the PR):
</p>
<blockquote><pre>
typedef basic_string&lt;char, char_traits&lt;char&gt;, A&lt;char&gt;&gt; stringA;
vector&lt;stringA, scoped_allocator_adaptor&lt;A&lt;stringA&gt;&gt;&gt; vs;
stringA s;

vs.emplace_back(s, 2);  // Ill-formed
</pre></blockquote>
<p>
The problem is that uses-allocator construction requires that we be able to pass an allocator to the constructor 
<code>stringA(s, 2, allocator)</code>, 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:
</p>
<blockquote><pre>
basic_string(const basic_string&amp; str, size_type pos, const Allocator&amp; a);
</pre></blockquote>

<p><i>[2016-01-05, Pablo comments]</i></p>

<p>
I've reconsidered and I think that the issue as stated, is NAD. I do not like the PR <em>at all</em>. In fact, I think it reverses 
a previous fix and it could break existing code.
<p/>
There are two patterns that are at work here:
</p>
<ol>
<li><p>Every constructor needs a version with and without an allocator argument (possibly through the use of default arguments).</p></li>
<li><p>Every constructor except the copy constructor for which an allocator is not provided uses a default-constructed allocator.</p></li>
</ol>
<p>
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.
</p>

<p><i>[2016-03 Jacksonville]</i></p>

<p>
Closed as NAD, noting that <a href="lwg-defects.html#2583" title="There is no way to supply an allocator for basic_string(str, pos) (Status: C++17)">2583</a><sup><a href="https://cplusplus.github.io/LWG/issue2583" title="Latest snapshot">(i)</a></sup> is a related issue.
</p>

<p><i>[2023-08-5; Arthur O'Dwyer comments]</i></p>

<p>
<a href="https://wg21.link/P2438" title=" std::string::substr() &amp;&amp;">P2438</a> added a constructor from <code>basic_string&amp;&amp;</code> 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.
</p>

<p>
<strong>Previous resolution [SUPERSEDED]:</strong>
</p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/N3936" title=" Working Draft, Standard for Programming Language C++">N3936</a>.</p>

<ol>
<li><p>Change 27.4.3 <a href="https://wg21.link/basic.string">[basic.string]</a> p5, class template <code>basic_string</code> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
<i>// 21.4.2, construct/copy/destroy:</i>
[&hellip;]
basic_string(basic_string&amp;&amp; str) noexcept;
<ins>basic_string(const basic_string&amp; str, size_type pos, size_type n = npos);</ins>
basic_string(const basic_string&amp; str, size_type pos, size_type n<del> = npos</del>,
            const Allocator&amp; a<del> = Allocator()</del>);
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Change 27.4.3.3 <a href="https://wg21.link/string.cons">[string.cons]</a> around p3 as indicated:</p>

<blockquote>
<pre>
<ins>basic_string(const basic_string&amp; str, 
             size_type pos, size_type n = npos);</ins>
basic_string(const basic_string&amp; str, 
             size_type pos, size_type n<del> = npos</del>,
             const Allocator&amp; a<del> = Allocator()</del>);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-5- <i>Effects</i>: Constructs an object of class <code>basic_string</code> and determines the effective length <code>rlen</code> of the
initial string value as the smaller of <code>n</code> and <code>str.size() - pos</code>, as indicated in Table 65. <ins>The first constructor 
obtains an allocator by calling <code>allocator_traits&lt;allocator_type&gt;::select_on_container_copy_construction</code> on the 
allocator belonging to <code>str</code>.</ins>
<p/>
Table 65 &mdash; <ins><code>basic_string(const basic_string&amp;, size_type, size_type)</code> and</ins>
<code>basic_string(const basic_string&amp;, size_type, size_type, const Allocator&amp;)</code> effects
</p>
</blockquote>
</blockquote>
</li>
</ol>
</blockquote>


<p id="res-2402"><b>Proposed resolution:</b></p>
<p>
The existing wording is intended.
</p>





</body>
</html>
