<!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.0-alpha/dist/katex.min.css" integrity="sha384-BTL0nVi8DnMrNdMQZG1Ww6yasK9ZGnUxL1ZWukXQ7fygA1py52yPp9W4wrR00VML" crossorigin="anonymous">
        <style>
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ body { font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback"; font-size: 14px; padding: 0 26px; line-height: 22px; word-wrap: break-word; } #code-csp-warning { position: fixed; top: 0; right: 0; color: white; margin: 16px; text-align: center; font-size: 12px; font-family: sans-serif; background-color:#444444; cursor: pointer; padding: 6px; box-shadow: 1px 1px 1px rgba(0,0,0,.25); } #code-csp-warning:hover { text-decoration: none; background-color:#007acc; box-shadow: 2px 2px 2px rgba(0,0,0,.25); } body.scrollBeyondLastLine { margin-bottom: calc(100vh - 22px); } body.showEditorSelection .code-line { position: relative; } body.showEditorSelection .code-active-line:before, body.showEditorSelection .code-line:hover:before { content: ""; display: block; position: absolute; top: 0; left: -12px; height: 100%; } body.showEditorSelection li.code-active-line:before, body.showEditorSelection li.code-line:hover:before { left: -30px; } .vscode-light.showEditorSelection .code-active-line:before { border-left: 3px solid rgba(0, 0, 0, 0.15); } .vscode-light.showEditorSelection .code-line:hover:before { border-left: 3px solid rgba(0, 0, 0, 0.40); } .vscode-light.showEditorSelection .code-line .code-line:hover:before { border-left: none; } .vscode-dark.showEditorSelection .code-active-line:before { border-left: 3px solid rgba(255, 255, 255, 0.4); } .vscode-dark.showEditorSelection .code-line:hover:before { border-left: 3px solid rgba(255, 255, 255, 0.60); } .vscode-dark.showEditorSelection .code-line .code-line:hover:before { border-left: none; } .vscode-high-contrast.showEditorSelection .code-active-line:before { border-left: 3px solid rgba(255, 160, 0, 0.7); } .vscode-high-contrast.showEditorSelection .code-line:hover:before { border-left: 3px solid rgba(255, 160, 0, 1); } .vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before { border-left: none; } img { max-width: 100%; max-height: 100%; } a { text-decoration: none; } a:hover { text-decoration: underline; } a:focus, input:focus, select:focus, textarea:focus { outline: 1px solid -webkit-focus-ring-color; outline-offset: -1px; } hr { border: 0; height: 2px; border-bottom: 2px solid; } h1 { padding-bottom: 0.3em; line-height: 1.2; border-bottom-width: 1px; border-bottom-style: solid; } h1, h2, h3 { font-weight: normal; } h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { font-size: inherit; line-height: auto; } table { border-collapse: collapse; } table > thead > tr > th { text-align: left; border-bottom: 1px solid; } table > thead > tr > th, table > thead > tr > td, table > tbody > tr > th, table > tbody > tr > td { padding: 5px 10px; } table > tbody > tr + tr > td { border-top: 1px solid; } blockquote { margin: 0 7px 0 5px; padding: 0 16px 0 10px; border-left-width: 5px; border-left-style: solid; } code { font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"; font-size: 14px; line-height: 19px; } body.wordWrap pre { white-space: pre-wrap; } .mac code { font-size: 12px; line-height: 18px; } pre:not(.hljs), pre.hljs code > div { padding: 16px; border-radius: 3px; overflow: auto; } /** Theming */ pre code { color: var(--vscode-editor-foreground); } .vscode-light pre:not(.hljs), .vscode-light code > div { background-color: rgba(220, 220, 220, 0.4); } .vscode-dark pre:not(.hljs), .vscode-dark code > div { background-color: rgba(10, 10, 10, 0.4); } .vscode-high-contrast pre:not(.hljs), .vscode-high-contrast code > div { background-color: rgb(0, 0, 0); } .vscode-high-contrast h1 { border-color: rgb(0, 0, 0); } .vscode-light table > thead > tr > th { border-color: rgba(0, 0, 0, 0.69); } .vscode-dark table > thead > tr > th { border-color: rgba(255, 255, 255, 0.69); } .vscode-light h1, .vscode-light hr, .vscode-light table > tbody > tr + tr > td { border-color: rgba(0, 0, 0, 0.18); } .vscode-dark h1, .vscode-dark hr, .vscode-dark table > tbody > tr + tr > td { border-color: rgba(255, 255, 255, 0.18); } 
</style>
<style>
/* Tomorrow Theme */ /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ /* Original theme - https://github.com/chriskempson/tomorrow-theme */ /* Tomorrow Comment */ .hljs-comment, .hljs-quote { color: #8e908c; } /* Tomorrow Red */ .hljs-variable, .hljs-template-variable, .hljs-tag, .hljs-name, .hljs-selector-id, .hljs-selector-class, .hljs-regexp, .hljs-deletion { color: #c82829; } /* Tomorrow Orange */ .hljs-number, .hljs-built_in, .hljs-builtin-name, .hljs-literal, .hljs-type, .hljs-params, .hljs-meta, .hljs-link { color: #f5871f; } /* Tomorrow Yellow */ .hljs-attribute { color: #eab700; } /* Tomorrow Green */ .hljs-string, .hljs-symbol, .hljs-bullet, .hljs-addition { color: #718c00; } /* Tomorrow Blue */ .hljs-title, .hljs-section { color: #4271ae; } /* Tomorrow Purple */ .hljs-keyword, .hljs-selector-tag { color: #8959a8; } .hljs { display: block; overflow-x: auto; color: #4d4d4c; padding: 0.5em; } .hljs-emphasis { font-style: italic; } .hljs-strong { font-weight: bold; }
</style>
<style>
.task-list-item { list-style-type: none; } .task-list-item-checkbox { margin-left: -20px; vertical-align: middle; }
</style>
        <style>
            body {
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'HelveticaNeue-Light', 'Ubuntu', 'Droid Sans', sans-serif;
                font-size: 14px;
                line-height: 1.6;
            }
        </style>
    </head>
    <body>
        <h1 id="fixing-allocator-usage-for-operatorbasicstring">Fixing allocator usage for <code>operator+(basic_string)</code></h1>
<table>
<thead>
<tr>
<th><a href=""></a></th>
<th><a href=""></a></th>
</tr>
</thead>
<tbody>
<tr>
<td>Paper number</td>
<td>P1165R0</td>
</tr>
<tr>
<td>Reply-to</td>
<td>Tim Song &lt;<a href="mailto:rs2740@gmail.com">rs2740@gmail.com</a>&gt;</td>
</tr>
<tr>
<td>Audience</td>
<td>LWG</td>
</tr>
</tbody>
</table>
<h2 id="abstract">Abstract</h2>
<p>Allocator propagation for <code>basic_string</code>'s <code>operator+</code> is haphazard, inconsistent, and a source of implementation divergence. Let's make it consistent.</p>
<h2 id="introduction">Introduction</h2>
<p>Let <code>lhs</code> and <code>rhs</code> be two <code>basic_string</code> lvalues with a <code>char</code> <code>value_type</code>. The following table shows the allocator used for the result for each of the 12 <code>operator+</code> overloads, in the working paper and three major implementations:</p>
<table>
<thead>
<tr>
<th>Expression</th>
<th>WP</th>
<th>libstdc++ (trunk)</th>
<th>libc++ (trunk)</th>
<th>MSVC STL (19.00.23506)</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>lhs + rhs</code></td>
<td><s>SOCCC on</s> SOCCC on <code>lhs</code></td>
<td>SOCCC on <code>lhs</code></td>
<td><code>lhs</code> (no SOCCC)</td>
<td>default-constructed</td>
</tr>
<tr>
<td><code>lhs + std::move(rhs)</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
</tr>
<tr>
<td><code>std::move(lhs) + rhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
</tr>
<tr>
<td><code>std::move(lhs) + std::move(rhs)</code></td>
<td><code>lhs</code> <s>&quot;or equivalently&quot; <code>rhs</code></s></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
</tr>
<tr>
<td><code>lhs + &quot;str&quot;</code></td>
<td>default-constructed</td>
<td>SOCCC on <code>lhs</code></td>
<td><code>lhs</code></td>
<td>default-constructed</td>
</tr>
<tr>
<td><code>lhs + 'c'</code></td>
<td>default-constructed</td>
<td>SOCCC on <code>lhs</code></td>
<td><code>lhs</code></td>
<td>default-constructed</td>
</tr>
<tr>
<td><code>std::move(lhs) + &quot;str&quot;</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
</tr>
<tr>
<td><code>std::move(lhs) + 'c'</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
<td><code>lhs</code></td>
</tr>
<tr>
<td><code>&quot;str&quot; + rhs</code></td>
<td>default-constructed</td>
<td>default-constructed</td>
<td><code>rhs</code></td>
<td>default-constructed</td>
</tr>
<tr>
<td><code>'c' + rhs</code></td>
<td>default-constructed</td>
<td>default-constructed</td>
<td><code>rhs</code></td>
<td>default-constructed</td>
</tr>
<tr>
<td><code>&quot;str&quot; + std::move(rhs)</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
</tr>
<tr>
<td><code>'c' + std::move(rhs)</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
<td><code>rhs</code></td>
</tr>
</tbody>
</table>
<p><small>(SOCCC == <code>select_on_container_copy_construction</code>. The <s>struckthrough</s> text is proposed to be removed by P1148R0.)</small></p>
<p>This is haphazard, inconsistent, and a source of implementation divergence.</p>
<h2 id="discussion">Discussion</h2>
<p>In the discussion of <a href="https://cplusplus.github.io/LWG/issue2402">LWG2402</a>, Pablo Halpern explained the patterns we use for constructors of allocator-aware containers (modifications mine):</p>
<blockquote>
<ul>
<li>Every constructor needs a version with and without an allocator argument (possibly through the use of default arguments).</li>
<li>Every constructor except the copy [and move] constructor[s] for which an allocator is not provided uses a default-constructed allocator.</li>
</ul>
</blockquote>
<p>Copy constructors obtain the allocator to use via <code>select_on_container_copy_construction</code>; move constructors obtain the allocator to use by move constructing from the source's allocator (which is equivalent to copy after <a href="https://wg21.link/lwg2593">LWG2593</a>).</p>
<p><code>operator+</code> constructs a new string, but it is not a copy or move constructor any more than <code>basic_string(const basic_string&amp;, size_t, size_t, const Allocator&amp;)</code>. Its operands are simply sources of characters. It should therefore consistently use a default-constructed allocator.</p>
<p>As a binary operator, it is not possible to add an allocator argument to <code>operator+</code>.  Designing a string concatenation API with allocator support is beyond the scope of this paper. Users desiring to control the allocator used for the result should therefore use the member functions of <code>basic_string</code> directly.</p>
<h2 id="proposed-wording">Proposed wording</h2>
<p>This wording is relative to <a href="https://wg21.link/n4762">N4762</a>.</p>
<p>Replace <code>[string.op+]</code> in its entirety with the following:</p>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">lhs</span>,
              <span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">rhs</span>);</span>

<span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">lhs</span>, <span class="hljs-title">const</span> <span class="hljs-title">charT</span>* <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>1</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(lhs, Allocator());
    r.append(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">lhs</span>,
              <span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">rhs</span>);</span>
<span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">lhs</span>, <span class="hljs-title">const</span> <span class="hljs-title">charT</span>* <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>2</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-built_in">std</span>::move(lhs), Allocator());
    r.append(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">lhs</span>,
              <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>3</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-built_in">std</span>::move(lhs), Allocator());
    r.append(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<p>except that both  <code>lhs</code> and <code>rhs</code> are left in valid but unspecified states.</p>
<blockquote>
<p><em>Drafting note</em>: The intent is to allow the implementation to move from either operand. — <em>end drafting note</em></p>
</blockquote>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">lhs</span>,
              <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">rhs</span>);</span>
<span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">charT</span>* <span class="hljs-title">lhs</span>, <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>4</sup> Effects: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-built_in">std</span>::move(rhs), Allocator());
    r.insert(<span class="hljs-number">0</span>, lhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">charT</span>* <span class="hljs-title">lhs</span>, <span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>5</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r = lhs;
    r.append(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">charT</span> <span class="hljs-title">lhs</span>, <span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>6</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-number">1</span>, lhs);
    r.append(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">charT</span> <span class="hljs-title">lhs</span>, <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>7</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-built_in">std</span>::move(rhs), Allocator());
    r.insert(r.begin(), lhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">const</span> <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp; <span class="hljs-title">lhs</span>, <span class="hljs-title">charT</span> <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>8</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(lhs, Allocator());
    r.push_back(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<pre class="hljs"><code><div><span class="hljs-keyword">template</span>&lt;<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">charT</span>, <span class="hljs-title">class</span> <span class="hljs-title">traits</span>, <span class="hljs-title">class</span> <span class="hljs-title">Allocator</span>&gt;
  <span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;
    <span class="hljs-title">operator</span>+(<span class="hljs-title">basic_string</span>&lt;charT, traits, Allocator&gt;&amp;&amp; <span class="hljs-title">lhs</span>, <span class="hljs-title">charT</span> <span class="hljs-title">rhs</span>);</span>
</div></code></pre>
<p><sup>9</sup> <em>Effects</em>: Equivalent to:</p>
<pre class="hljs"><code><div>    basic_string&lt;charT, traits, Allocator&gt; r(<span class="hljs-built_in">std</span>::move(lhs), Allocator());
    r.push_back(rhs);
    <span class="hljs-keyword">return</span> r;
</div></code></pre>
<!--
## Appendix

### Testing code

```c++
#include <string>
#include <cstdlib>
#include <new>
#include <iostream>

template <class T>
struct Mallocator {
  typedef T value_type;
  Mallocator() : i(100 * dtag++) { }
  explicit Mallocator(int i) : i(i) {}
  Mallocator(const Mallocator& o) = default;
  template <class U> constexpr Mallocator(const Mallocator<U>& u) noexcept : i(u.i) {}
  [[nodiscard]] T* allocate(std::size_t n) {
    if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
    if(auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) return p;
    throw std::bad_alloc();
  }
  void deallocate(T* p, std::size_t) noexcept { std::free(p); }
  Mallocator select_on_container_copy_construction() const { return Mallocator(i * 1000); };
  inline static int dtag = 1;
  int i;
};
template <class T, class U>
bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
template <class T, class U>
bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }


int main() {
    std::basic_string<char, std::char_traits<char>, Mallocator<char>> l, r;
    #define PALLOC(l, r) std::cout << #l " + "  #r ": "<< (l + r).get_allocator().i << '\n'
    PALLOC(l, r);
    PALLOC(l, std::move(r));
    PALLOC(std::move(l), r);
    PALLOC(std::move(l), std::move(r));
    PALLOC(l, "str");
    PALLOC(l, 'c');
    PALLOC(std::move(l), "str");
    PALLOC(std::move(l), 'c');
    PALLOC("str", r);
    PALLOC('c', r);
    PALLOC("str", std::move(r));
    PALLOC('c', std::move(r));
}
```
-->
    </body>
    </html>