<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2070: allocate_shared should use allocator_traits&lt;A&gt;::construct</title>
<meta property="og:title" content="Issue 2070: allocate_shared should use allocator_traits&lt;A&gt;::construct">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2070.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#Resolved">Resolved</a> status.</em></p>
<h3 id="2070"><a href="lwg-defects.html#2070">2070</a>. <code>allocate_shared</code> should use <code>allocator_traits&lt;A&gt;::construct</code></h3>
<p><b>Section:</b> 20.3.2.2.7 <a href="https://wg21.link/util.smartptr.shared.create">[util.smartptr.shared.create]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Jonathan Wakely <b>Opened:</b> 2011-07-11 <b>Last modified:</b> 2017-07-16</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#util.smartptr.shared.create">issues</a> in [util.smartptr.shared.create].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>
<p>
20.3.2.2.7 <a href="https://wg21.link/util.smartptr.shared.create">[util.smartptr.shared.create]</a> says:
</p>
<blockquote><p>
-2- <i>Effects</i>: Allocates memory suitable for an object of type <code>T</code> and constructs an object in that memory
via the placement new expression <code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code>. The template
<code>allocate_shared</code> uses a copy of a to allocate memory. If an exception is thrown, the functions have
no effect.
</p></blockquote>
<p>
This explicitly requires placement new rather than using
<code>allocator_traits&lt;A&gt;::construct(a, (T*)pv, std::forward&lt;Args&gt;(args)...)</code>
In most cases that would result in the same placement new expression,
but would allow more control over how the object is constructed e.g.
using <code>scoped_allocator_adaptor</code> to do uses-allocator construction, or
using an allocator declared as a friend to construct objects with no
public constructors.
</p>

<p><i>[2011-08-16 Bloomington:]</i></p>

<p>
Agreed to fix in principle, but believe that <code>make_shared</code> and
<code>allocate_shared</code> have now diverged enough that their descriptions
should be separated.  Pablo and Stefanus to provide revised wording.
</p>

<p><strong>Daniel's (old) proposed resolution:</strong></p>
<blockquote class="note">
<p>This wording is relative to the FDIS.</p>

<ol>
<li><p>Change the following paragraphs of 20.3.2.2.7 <a href="https://wg21.link/util.smartptr.shared.create">[util.smartptr.shared.create]</a> as indicated (The suggested
removal of the last sentence of p1 is not strictly required to resolve this issue, but is still recommended,
because it does not say anything new but may give the impression that it says something new):
</p><blockquote><pre>
template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args);
template&lt;class T, class A, class... Args&gt;
  shared_ptr&lt;T&gt; allocate_shared(const A&amp; a, Args&amp;&amp;... args);
</pre><blockquote>
<p>
-1- <i>Requires</i>: <ins>For the template <code>make_shared</code>, t</ins><del>T</del>he expression 
<code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code>, where <code>pv</code> 
has type <code>void*</code> and points to storage suitable to hold an object of type <code>T</code>, shall be well 
formed. <ins>For the template <code>allocate_shared</code>, the expression 
<code>allocator_traits&lt;A&gt;::construct(a, pt, std::forward&lt;Args&gt;(args)...)</code>,
where <code>pt</code> has type <code>T*</code> and points to storage suitable to hold an object
of type <code>T</code>, shall be well formed.</ins> <code>A</code> shall be an allocator ([allocator.requirements]). 
<del>The copy constructor and destructor of  <code>A</code> shall not throw exceptions.</del>
<p/>
-2- <i>Effects</i>: Allocates memory suitable for an object of type <code>T</code> and constructs an object in 
that memory<ins>. The template <code>make_shared</code> constructs the object</ins> via the placement new expression 
<code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code>. The template <code>allocate_shared</code> uses a copy 
of <code>a</code> to allocate memory<ins> and constructs the object by calling <code>allocator_traits&lt;A&gt;::construct(a, pt,
std::forward&lt;Args&gt;(args)...)</code></ins>. If an exception is thrown, the functions have no effect.
<p/>
-3- <i>Returns</i>: A <code>shared_ptr</code> instance that stores and owns the address of the newly constructed 
object of type <code>T</code>.
<p/>
-4- <i>Postconditions</i>: <code>get() != 0 &amp;&amp; use_count() == 1</code>
<p/>
-5- <i>Throws</i>: <code>bad_alloc</code>, or<ins>, for the template <code>make_shared</code>, an exception thrown from
the constructor of <code>T</code>, or, for the template <code>allocate_shared</code>,</ins> an exception thrown from 
<code>A::allocate</code> or <ins>from <code>allocator_traits&lt;A&gt;::construct</code></ins><del>from the constructor of 
<code>T</code></del>.
<p/>
-6- <i>Remarks</i>: Implementations are encouraged, but not required, to perform no more than one memory
allocation. [ <i>Note</i>: This provides efficiency equivalent to an intrusive smart pointer. &mdash; <i>end note</i> ]
<p/>
-7- [ <i>Note</i>: These functions will typically allocate more memory than <code>sizeof(T)</code> to allow for internal
bookkeeping structures such as the reference counts. &mdash; <i>end note</i> ]
</p>
</blockquote></blockquote>
</li>
</ol>
</blockquote>

<p><i>[2011-12-04: Jonathan and Daniel improve wording]</i></p>


<p>See also c++std-lib-31796</p>




<p><i>[2013-10-13, Ville]</i></p>

<p>
This issue is related to <a href="lwg-defects.html#2089" title="std::allocator::construct should use uniform initialization (Status: Resolved)">2089</a><sup><a href="https://cplusplus.github.io/LWG/issue2089" title="Latest snapshot">(i)</a></sup>.
</p>


<p><i>[2014-02-15 post-Issaquah session : move to Tentatively NAD]</i></p>

<p>STL: This takes an allocator, but then ignores its construct. That's squirrely.</p>
<p>Alisdair: The convention is when you take an allocator, you use its construct.</p>
<p>STL: 23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a>/3, argh! This fills me with despair, but I understand it now.</p>
<p>STL: Ok, this is some cleanup.</p>
<p>STL: You're requiring <code>b</code> to be of type <code>A</code> and not being rebound, is that an overspecification?</p>
<p>Pablo: Good point. Hmm, that's only a requirement on what must be well-formed.</p>
<p>STL: If it's just a well-formed requirement, then why not just use a directly?</p>
<p>Pablo: Yeah, the well-formed requirement is overly complex. It's not a real call, we could just use a directly. It makes it harder to read.</p>
<p>Alisdair: <code>b</code> should be an allocator in the same family as <code>a</code>.</p>
<p>Pablo: This is a well-formed requirement, I wonder if it's the capital A that's the problem here. It doesn't matter here, this is way too much wording.</p>
<p>Alisdair: It's trying to tie the constructor arguments into the allocator requirements.</p>
<p>Pablo: <code>b</code> could be struck, that's a runtime quality. The construct will work with anything that's in the family of <code>A</code>.</p>
<p>Alisdair: The important part is the <code>forward</code> of <code>Args</code>.</p>
<p>Pablo: <code>A</code> must be an allocator, and <code>forward</code> <code>Args</code> must work with that.</p>
<p>Alisdair: First let's nail down <code>A</code>.</p>
<p>Pablo: Then replace <code>b</code> with <code>a</code>, and strike the rest.</p>
<p>STL: You need <code>pt</code>'s type, at least.</p>
<p>Pablo: There's nothing to be said about runtime constraints here, this function doesn't even take a <code>pt</code>.</p>
<p>STL: Looking at the Effects, I believe <code>b</code> is similarly messed up, we can use <code>a2</code> to construct an object.</p>
<p>Alisdair: Or any allocator in the family of <code>a</code>.</p>
<p>STL: We say this stuff for the deallocate too, it should be lifted up.</p>
<p>STL: "owns the address" is weird.</p>
<p>Alisdair: shared_ptr owns pointers, although it does sound funky.</p>
<p>Walter: "to destruct" is ungrammatical.</p>
<p>STL: "When ownership is given up" is not what we usually say.</p>
<p>Alisdair: I think the Returns clause is the right place to say this.</p>
<p>STL: The right place to say this is <code>shared_ptr</code>'s dtor, we don't want to use Core's "come from" convention.</p>
<p>Alisdair: I'm on the hook to draft cleaner wording.</p>


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

<p>
AM: I was going to clean up the wording, but haven't done it yet.<br/>
Defer until we have new wording.<br/>
</p>

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

<p>
Alisdair: we need to figure out whether we should call construct or not; major implementation divergence<br/>
STL: this does not grant friendship, does it?<br/>
Jonathan: some people want it.<br/>
Thomas: scoped allocator adapter should be supported, so placement new doesn't work<br/>
Alisdair: this makes the make_ functions impossible<br/>
Thomas: you don't want to use those though.<br/>
Alisdair: but people use that today, at Bloomberg<br/>
Alisdair: and what do we do about fancy pointers?<br/>
Jonathan: we constrain it to only non-fancy pointers.<br/>
STL: shared_ptr has never attempted to support fancy pointers; seems like a paper is needed.<br/>
Poll: call construct:6 operator new: 0 don't care: 4<br/>
Poll: should we support fancy pointers? Yes: 1 No: 4 don't care: 4<br/>
STL: 20.8.2.2.6p2: 'and pv->~T()' is bogus for void<br/>
STL: 20.8.2.2.6p4: is this true even if we're going to allocate a bit more?<br/>
Alisdair: yes<br/>
Alisdair: coming up with new wording<br/>
</p>

<p><i>[2016-08, Chicago Monday PM]</i></p>

<p>Alisdair to provide new wording this week</p>

<p><i>[2017-07 Toronto]</i></p>

<p>Resolved by the adoption of <a href="https://wg21.link/P0674R1">P0674R1</a> in Toronto</p>


<p id="res-2070"><b>Proposed resolution:</b></p>
<p>This wording is relative to the FDIS.</p>

<ol>
<li><p>Change the following paragraphs of 20.3.2.2.7 <a href="https://wg21.link/util.smartptr.shared.create">[util.smartptr.shared.create]</a> as indicated:
</p>
<blockquote><pre>
template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args);
<del>template&lt;class T, class A, class... Args&gt;
  shared_ptr&lt;T&gt; allocate_shared(const A&amp; a, Args&amp;&amp;... args);</del>
</pre></blockquote>
<p>
<del>-1- <i>Requires</i>: The expression <code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code>, where <code>pv</code> 
has type <code>void*</code> and points to storage suitable to hold an object of type <code>T</code>, shall be well 
formed. <code>A</code> shall be an allocator (16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>). The copy constructor 
and destructor of <code>A</code> shall not throw exceptions.</del>
<p/>
-2- <i>Effects</i>: <ins>Equivalent to</ins>
</p>
<blockquote><pre> 
<ins>return allocate_shared&lt;T&gt;(allocator&lt;T&gt;(), std::forward&lt;Args&gt;(args)...);</ins>
</pre></blockquote>
<p>
<del>Allocates memory suitable for an object of type <code>T</code> 
and constructs an object in that memory via the placement new expression 
<code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code>. The template <code>allocate_shared</code> uses a copy 
of <code>a</code> to allocate memory. If an exception is thrown, the functions have no effect.</del>
<p/>
<ins>-?- <i>Remarks</i>: An implementation may meet the effects (and the implied guarantees) without 
creating the allocator object [<i>Note</i>: That is, user-provided specializations of <code>std::allocator</code>
may not be instantiated, the expressions <code>::new (pv) T(std::forward&lt;Args&gt;(args)...)</code> and 
<code>pv-&gt;~T()</code> may be evaluated directly &mdash; <i>end note</i>].</ins>
<p/>
<del>-3- <i>Returns</i>: A <code>shared_ptr</code> instance that stores and owns the address of the newly constructed 
object of type <code>T</code>.</del>
<p/>
<del>-4- <i>Postconditions</i>: <code>get() != 0 &amp;&amp; use_count() == 1</code></del>
<p/>
<del>-5- <i>Throws</i>: <code>bad_alloc</code>, or an exception thrown from <code>A::allocate</code> or from the 
constructor of <code>T</code>.</del>
<p/>
<del>-6- <i>Remarks</i>: Implementations are encouraged, but not required, to perform no more than one memory
allocation. [<i>Note</i>: This provides efficiency equivalent to an intrusive smart pointer. &mdash; <i>end note</i>]</del>
<p/>
<del>-7- [<i>Note</i>: These functions will typically allocate more memory than <code>sizeof(T)</code> to allow 
for internal bookkeeping structures such as the reference counts. &mdash; <i>end note</i>]</del>
</p>
</li>
<li><p>
Add the following set of <ins>new paragraphs</ins> immediately following the previous paragraph 7 of
20.3.2.2.7 <a href="https://wg21.link/util.smartptr.shared.create">[util.smartptr.shared.create]</a>:
</p>
<blockquote><pre>
template&lt;class T, class A, class... Args&gt;
  shared_ptr&lt;T&gt; allocate_shared(const A&amp; a, Args&amp;&amp;... args);
</pre></blockquote>
<p>
-?- <i>Requires</i>: The expressions 
<code>allocator_traits&lt;A&gt;::construct(b, pt, std::forward&lt;Args&gt;(args)...)</code> and
<code>allocator_traits&lt;A&gt;::destroy(b, pt)</code> shall be well-formed and well-defined, 
where <code>b</code> has type <code>A</code> and is a copy of <code>a</code> and where <code>pt</code> 
has type <code>T*</code> and points to storage suitable to hold an object of type <code>T</code>. 
<code>A</code> shall meet the allocator requirements (16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a>). 
<p/>
-?- <i>Effects</i>: Uses an object <code>a2</code> 
of type <code>allocator_traits&lt;A&gt;::rebind_alloc&lt;<i>unspecified</i>&gt;</code> that compares equal to 
<code>a</code> to allocate memory suitable for an object of type <code>T</code>. 
Uses a copy <code>b</code> of type <code>A</code> from <code>a</code> to construct an object of type <code>T</code> in 
that memory by calling <code>allocator_traits&lt;A&gt;::construct(b, pt, std::forward&lt;Args&gt;(args)...)</code>. 
If an exception is thrown, the function has no effect.
<p/>
-?- <i>Returns</i>: A <code>shared_ptr</code> instance that stores and owns the address of the newly constructed 
object of type <code>T</code>. When ownership is given up, the effects are as follows: Uses a copy <code>b2</code> 
of type <code>A</code> from <code>a</code> to destruct an object of type <code>T</code> by calling 
<code>allocator_traits&lt;A&gt;::destroy(b2, pt2)</code> where <code>pt2</code> has type <code>T*</code> 
and refers to the newly constructed object. Then uses an object of type
<code>allocator_traits&lt;A&gt;::rebind_alloc&lt;<i>unspecified</i>&gt;</code> that compares equal to 
<code>a</code> to deallocate the allocated memory.
<p/>
-?- <i>Postconditions</i>: <code>get() != 0 &amp;&amp; use_count() == 1</code>
<p/>
-?- <i>Throws</i>: Nothing unless memory allocation or <code>allocator_traits&lt;A&gt;::construct</code> 
throws an exception.
<p/>
-?- <i>Remarks</i>: Implementations are encouraged, but not required, to perform no more than one memory 
allocation. [<i>Note</i>: Such an implementation provides efficiency equivalent to an intrusive smart 
pointer. &mdash; <i>end note</i>]
<p/>
-?- [<i>Note</i>: This function will typically allocate more memory than <code>sizeof(T)</code> to allow for internal
bookkeeping structures such as the reference counts. &mdash; <i>end note</i>]
</p>
</li>
</ol>





</body>
</html>
