<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2996: Missing rvalue overloads for shared_ptr operations</title>
<meta property="og:title" content="Issue 2996: Missing rvalue overloads for shared_ptr operations">
<meta property="og:description" content="C++ library issue. Status: C++20">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2996.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#C++20">C++20</a> status.</em></p>
<h3 id="2996"><a href="lwg-defects.html#2996">2996</a>. Missing rvalue overloads for <code>shared_ptr</code> operations</h3>
<p><b>Section:</b> 20.3.2.2 <a href="https://wg21.link/util.smartptr.shared">[util.smartptr.shared]</a>, 20.3.2.2.10 <a href="https://wg21.link/util.smartptr.shared.cast">[util.smartptr.shared.cast]</a> <b>Status:</b> <a href="lwg-active.html#C++20">C++20</a>
 <b>Submitter:</b> Geoffrey Romer <b>Opened:</b> 2017-07-07 <b>Last modified:</b> 2021-02-25</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#util.smartptr.shared">issues</a> in [util.smartptr.shared].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++20">C++20</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The <code>shared_ptr</code> aliasing constructor and the <code>shared_ptr</code> casts are specified to take a <code>shared_ptr</code> 
by <code>const</code> reference and construct a new <code>shared_ptr</code> that shares ownership with it, and yet they have no 
corresponding rvalue reference overloads. That results in an unnecessary refcount increment/decrement when those operations 
are given an rvalue. Rvalue overloads can't be added as a conforming extension because they observably change semantics 
(but mostly only for code that does unreasonable things like pass an argument by move and then rely on the fact that it's 
unchanged), and [res.on.arguments]/p1.3 doesn't help because it only applies to rvalue reference parameters.
<p/>
This issue is related to <a href="https://wg21.link/p0390r0">P0390R0</a>.
</p>

<p><i>[2017-07 Toronto Tuesday PM issue prioritization]</i></p>

<p>Status LEWG</p>

<p><i>[2018-06 Rapperswil Monday AM]</i></p>

<p>Move to Ready; choosing the PR in the issue as opposed to <a href="https://wg21.link/P0390R0">P0390R0</a>
and rebase wording to most recent working draft</p>
<p><i>[2018-11, Adopted in San Diego]</i></p>



<p id="res-2996"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/n4750">N4750</a>.
</p>

<ol>
<li><p>Edit 20.2.2 <a href="https://wg21.link/memory.syn">[memory.syn]</a>, header <code>&lt;memory&gt;</code> synopsis, as indicated:</p>
<blockquote>
<pre>
[&hellip;]
<i>// 20.3.2.2.10 <a href="https://wg21.link/util.smartptr.shared.cast">[util.smartptr.shared.cast]</a>,</i> shared_ptr <i>casts</i>
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; static_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; static_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; dynamic_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; dynamic_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; const_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; const_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; reinterpret_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; reinterpret_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Edit 20.3.2.2 <a href="https://wg21.link/util.smartptr.shared">[util.smartptr.shared]</a>, class template <code>shared_ptr</code> synopsis, as indicated:</p>

<blockquote>
<pre>
template&lt;class T&gt; class shared_ptr {
public:
  [&hellip;]
  <i>// 20.3.2.2.2 <a href="https://wg21.link/util.smartptr.shared.const">[util.smartptr.shared.const]</a>, constructors</i>
  [&hellip;]
  template &lt;class D, class A&gt; shared_ptr(nullptr_t p, D d, A a);
  template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r, element_type* p) noexcept;
  <ins>template&lt;class Y&gt; shared_ptr(shared_ptr&lt;Y&gt;&amp;&amp; r, element_type* p) noexcept;</ins>
  shared_ptr(const shared_ptr&amp; r) noexcept;
  [&hellip;]
};
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Edit 20.3.2.2.2 <a href="https://wg21.link/util.smartptr.shared.const">[util.smartptr.shared.const]</a> as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> the <code>use_count()</code> postcondition can safely be deleted because it is redundant with 
the "shares ownership" wording in the <i>Effects</i>. &mdash; <i>end drafting note</i>]
</p>
</blockquote>

<blockquote>
<pre>
template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r, element_type* p) noexcept;
<ins>template&lt;class Y&gt; shared_ptr(shared_ptr&lt;Y&gt;&amp;&amp; r, element_type* p) noexcept;</ins>
</pre>
<blockquote>
<p>
-14- <i>Effects:</i> Constructs a <code>shared_ptr</code> instance that stores <code>p</code> and shares ownership with 
<ins>the initial value of</ins> <code>r</code>.
<p/>
-15- <i>Postconditions:</i> <code>get() == p <del>&amp;&amp; use_count() == r.use_count()</del></code>. <ins>For the 
second overload, <code>r</code> is empty and <code>r.get() == nullptr</code>.</ins>
<p/>
-16- [<i>Note:</i> To avoid the possibility of a dangling pointer, the user of this constructor must ensure that <code>p</code>
remains valid at least until the ownership group of <code>r</code> is destroyed. &mdash; <i>end note</i>]
<p/>
-17- [<i>Note:</i> This constructor allows creation of an empty <code>shared_ptr</code> instance with a non-null stored pointer.
&mdash; <i>end note</i>]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Edit 20.3.2.2.10 <a href="https://wg21.link/util.smartptr.shared.cast">[util.smartptr.shared.cast]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; static_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; static_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
</pre>
<blockquote>
<p>
-1- <i>Requires:</i> The expression <code>static_cast&lt;T*&gt;((U*)nullptr)</code> shall be well-formed.
<p/>
-2- <i>Returns:</i> 
<blockquote>
<code>shared_ptr&lt;T&gt;(<del>r</del><ins><i>R</i></ins>, static_cast&lt;typename 
  shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>
</blockquote>
<ins>, where <code><i>R</i></code> 
is <code>r</code> for the first overload, and <code>std::move(r)</code> for the second.</ins>
<p/>
-3- [<i>Note:</i> The seemingly equivalent expression <code>shared_ptr&lt;T&gt;(static_cast&lt;T*&gt;(r.get()))</code> 
will eventually result in undefined behavior, attempting to delete the same object twice. &mdash; <i>end note</i>]
</p>
</blockquote>
<pre>
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; dynamic_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; dynamic_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
</pre>
<blockquote>
<p>
-4- <i>Requires:</i> The expression <code>dynamic_cast&lt;T*&gt;((U*)nullptr)</code> shall be well-formed. The 
expression <code>dynamic_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get())</code> shall be well formed 
and shall have well-defined behavior.
<p/>
-5- <i>Returns:</i>
</p>
<ol style="list-style-type: none">
<li><p>(5.1) &mdash; When <code>dynamic_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get())</code> returns 
a non-null value <code>p</code>, <code>shared_ptr&lt;T&gt;(<del>r</del><ins><i>R</i></ins>, p)</code><ins>, where 
<code><i>R</i></code> is <code>r</code> for the first overload, and <code>std::move(r)</code> for the second</ins>.</p></li>
<li><p>(5.2) &mdash; Otherwise, <code>shared_ptr&lt;T&gt;()</code>.</p></li>
</ol>
<p>
-6- [<i>Note:</i> The seemingly equivalent expression <code>shared_ptr&lt;T&gt;(dynamic_cast&lt;T*&gt;(r.get()))</code> 
will eventually result in undefined behavior, attempting to delete the same object twice. &mdash; <i>end note</i>]
</p>
</blockquote>
<pre>
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; const_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; const_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
</pre>
<blockquote>
<p>
-7- <i>Requires:</i> The expression <code>const_cast&lt;T*&gt;((U*)nullptr)</code> shall be well-formed.
<p/>
-8- <i>Returns:</i> 
<blockquote>
<code>shared_ptr&lt;T&gt;(<del>r</del><ins><i>R</i></ins>, const_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>
</blockquote>
<ins>, where <code><i>R</i></code> is <code>r</code> for the first overload, and <code>std::move(r)</code> 
for the second.</ins>
<p/>
-9- [<i>Note:</i> The seemingly equivalent expression <code>shared_ptr&lt;T&gt;(const_cast&lt;T*&gt;(r.get()))</code> 
will eventually result in undefined behavior, attempting to delete the same object twice. &mdash; <i>end note</i>]
</p>
</blockquote>
<pre>
template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; reinterpret_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
  shared_ptr&lt;T&gt; reinterpret_pointer_cast(shared_ptr&lt;U&gt;&amp;&amp; r) noexcept;</ins>
</pre>
<blockquote>
<p>
-10- <i>Requires:</i> The expression <code>reinterpret_cast&lt;T*&gt;((U*)nullptr)</code> shall be well-formed.
<p/>
-11- <i>Returns:</i> 
<blockquote>
<code>shared_ptr&lt;T&gt;(<del>r</del><ins><i>R</i></ins>, reinterpret_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>
</blockquote>
<ins>, where <code><i>R</i></code> is <code>r</code> for the first overload, and <code>std::move(r)</code> 
for the second.</ins>
<p/>
-12- [<i>Note:</i> The seemingly equivalent expression <code>shared_ptr&lt;T&gt;(reinterpret_cast&lt;T*&gt;(r.get()))</code> 
will eventually result in undefined behavior, attempting to delete the same object twice. &mdash; <i>end note</i>]
</p>
</blockquote>
</blockquote>
</li>

</ol>




</body>
</html>
