<html><head><meta charset="UTF-8">
<title>Merging shared_ptr changes from Library Fundamentals to C++17</title>
  <style type='text/css'>
  body {font-variant-ligatures: none;}
  p {text-align:justify}
  li {text-align:justify}
  blockquote.note, div.note
  {
          background-color:#E0E0E0;
          padding-left: 15px;
          padding-right: 15px;
          padding-top: 1px;
          padding-bottom: 1px;
  }
  p code {color:navy}
  ins p code {color:#00A000}
  p ins code {color:#00A000}
  p del code {color:#A00000}
  ins {color:#00A000}
  del {color:#A00000}
  table#boilerplate { border:0 }
  table#boilerplate td { padding-left: 2em }
  table.bordered, table.bordered th, table.bordered td {
    border: 1px solid;
    text-align: center;
  }
  ins.block {color:#00A000; text-decoration: none}
  del.block {color:#A00000; text-decoration: none}
  </style>
</head><body>
<table id="boilerplate">
<tr><td>Document number</td><td>P0414R1</td></tr>
<tr><td>Date</td><td>2016-10-06</td></tr>
<tr><td>Project</td><td>Programming Language C++, Library Working Group</td></tr>
<tr><td>Reply-to</td><td>Jonathan Wakely &lt;cxx&#x40;kayari.org&gt;</td></tr>
</table><hr>
<h1>Merging shared_ptr changes from Library Fundamentals to C++17</h1>
<h2>Revision History</h2>

<p>Changes since P0414R0, following LWG review in Chicago, and LWG telecon:</p>

<ul>
<li>For <code>operator[]</code> removed <code>noexcept</code> and replaced with "<em>Throws:</em> Nothing." This is a change from the TS in order to adhere to the guidelines used for the IS.</li>
<li>For <code>operator-&gt;</code> changed the first new paragraph from "When <code>T</code> is an array type or (possibly cv-qualified) <code>void</code>" to the correct wording from P0220R1: "<em>Remarks:</em> When <code>T</code> is an array type".</li>
</ul>


<h2>Introduction</h2>

<p>LWG Motion 6 in Jacksonville was to apply to the C++ working paper
the wording from <a href="http://wg21.link/p0220r1">P0220R1</a>,
<em>Adopt Library Fundamentals V2 TS Components for C++17 (R1)</em>,
but due to conflicts with changes in the C++ WP the <code>shared_ptr</code> changes
were not applied.</p>

<p>I offered to write this paper showing the changes relative to the current WP.
I failed to do so before Oulu in time for the CD, but provide it now.</p>

<h2>Proposed Wording</h2>

<p>Changes are relative to N4594. Clauses have been renumbered since that draft,
so cross-references are given using <strong>[stable.names]</strong> for clarity.</p>

<p>Modify the class synopsis in 20.10.2.2 Class template <code>shared_ptr</code> [util.smartptr.shared]:</p>

<pre><code>  namespace std {
    template&lt;class T&gt; class shared_ptr {
    public:

      <del>typedef T element_type;</del>
      <ins>using element_type = remove_extent_t&lt;T&gt;;</ins>

      [...]

      // 20.10.2.2.5, observers:
      <del>T</del><ins>element_type</ins>* get() const noexcept;
      T&amp; operator*() const noexcept;
      T* operator-&gt;() const noexcept;
      <ins>element_type&amp; operator[](ptrdiff_t i) const;</ins>
      long use_count() const noexcept;
      bool unique() const noexcept;
      explicit operator bool() const noexcept;
      template&lt;class U&gt; bool owner_before(shared_ptr&lt;U&gt; const&amp; b) const;
      template&lt;class U&gt; bool owner_before(weak_ptr&lt;U&gt; const&amp; b) const;
    };

    [...]

    // 20.10.2.2.9, shared_ptr casts:
    template&lt;class T, class U&gt;
      shared_ptr&lt;T&gt; static_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
    template&lt;class T, class U&gt;
      shared_ptr&lt;T&gt; dynamic_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
    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;</ins>
      <ins>shared_ptr&lt;T&gt; reinterpret_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;</ins>
</code></pre>

<p>Add a new paragraph at the end of 20.10.2.2 Class template <code>shared_ptr</code> [util.smartptr.shared]:</p>

<blockquote><p><ins> -5- For the purposes of subclause <strong>[util.smartptr]</strong>, a pointer type <code>Y*</code> is said to be <em>compatible with</em> a pointer type <code>T*</code> when either <code>Y*</code> is convertible to <code>T*</code> or <code>Y</code> is <code>U[N]</code> and <code>T</code> is <code>U</code> <em>cv</em> <code>[]</code>. </ins></p></blockquote>

<p>Change 20.10.2.2.1 <code>shared_ptr</code> constructors [util.smartptr.shared.const]:</p>

<blockquote><pre><code>  template&lt;class Y&gt; explicit shared_ptr(Y* p);
</code></pre>

<p>-4-
_Requires: <del>p shall be convertible to T*.</del> <code>Y</code> shall be a complete type. The expression <del><code>delete p</code></del> <ins><code>delete[] p</code>, when <code>T</code> is an array type, or <code>delete p</code>, when <code>T</code> is not an array type,</ins>  shall be well formed, shall have well defined behavior, and shall not throw exceptions.
<ins> When <code>T</code> is <code>U[N]</code>, <code>Y(*)[N]</code> shall be convertible to <code>T*</code>; when <code>T</code> is <code>U[]</code>, <code>Y(*)[]</code> shall be convertible to <code>T*</code>; otherwise, <code>Y*</code> shall be convertible to <code>T*</code>. </ins></p>

<p>-5-
<em>Effects:</em> <del>C</del><ins>When <code>T</code> is not an array type, c</ins>onstructs a <code>shared_ptr</code> object that <em>owns</em> the pointer <code>p</code>.
<ins> Otherwise, constructs a <code>shared_ptr</code> that owns <code>p</code> and a deleter of an unspecified type that calls <code>delete[] p</code>. </ins>
Enables <code>shared_from_this</code> with <code>p</code>.
If an exception is thrown, <code>delete p</code> is called <ins> when <code>T</code> is not an array type, <code>delete[] p</code> otherwise</ins>.</p>

<p>-6-
<em>Postconditions:</em> <code>use_count() == 1 &amp;&amp; get() == p</code>.</p>

<p>-7-
<em>Throws:</em> <code>bad_alloc</code>, or an implementation-defined exception when a resource other than memory could not be obtained.</p>

<pre><code>  template&lt;class Y, class D&gt; shared_ptr(Y* p, D d);
  template&lt;class Y, class D, class A&gt; shared_ptr(Y* p, D d, A a);
  template &lt;class D&gt; shared_ptr(nullptr_t p, D d);
  template &lt;class D, class A&gt; shared_ptr(nullptr_t p, D d, A a);
</code></pre>

<p>-8-
<em>Requires:</em>
<del><code>p</code> shall be convertible to <code>T*</code>.</del>
<code>D</code> shall be <code>CopyConstructible</code>.
The copy constructor and destructor of <code>D</code> shall not throw exceptions.
The expression <code>d(p)</code> shall be well formed, shall have well defined behavior, and shall not throw exceptions.
<code>A</code> shall be an allocator (17.6.3.5).
The copy constructor and destructor of <code>A</code> shall not throw exceptions.
<ins> When <code>T</code> is <code>U[N]</code>, <code>Y(*)[N]</code> shall be convertible to <code>T*</code>; when <code>T</code> is <code>U[]</code>, <code>Y(*)[]</code> shall be convertible to <code>T*</code>; otherwise, <code>Y*</code> shall be convertible to <code>T*</code>. </ins></p>

<p>-9-
<em>Effects:</em> Constructs a <code>shared_ptr</code> object that <em>owns</em> the object <code>p</code> and the deleter <code>d</code>.
The first and second constructors enable <code>shared_from_this</code> with <code>p</code>.
The second and fourth constructors shall use a copy of <code>a</code> to allocate memory for internal use.
If an exception is thrown, <code>d(p)</code> is called.</p>

<p>-10-
<em>Postconditions:</em> <code>use_count() == 1 &amp;&amp; get() == p</code>.</p>

<p>-11-
<em>Throws:</em> <code>bad_alloc</code>, or an implementation-defined exception when a resource other than memory could not be obtained.</p>

<pre><code>  template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r, <del>T</del><ins>element_type</ins>* p) noexcept;
</code></pre>

<p>-12- <em>Effects:</em> [...]</p>

<p>-13- <em>Postconditions:</em> [...]</p>

<p>-14- [<em>Note:</em> [...]</p>

<p>-15- [<em>Note:</em> [...]</p>

<pre><code>  shared_ptr(const shared_ptr&amp; r) noexcept;
  template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r) noexcept;
</code></pre>

<p>-16-
<em>Remark:</em> The second constructor shall not participate in overload resolution unless <code>Y*</code> is <del>implicitly convertible to</del> <ins> <em>compatible with</em> </ins> <code>T*</code>.</p>

<p>-17- <em>Effects:</em> [...]</p>

<p>-18- <em>Postconditions:</em> [...]</p>

<pre><code>  shared_ptr(shared_ptr&amp;&amp; r) noexcept;
  template&lt;class Y&gt; shared_ptr(shared_ptr&lt;Y&gt;&amp;&amp; r) noexcept;
</code></pre>

<p>-19-
<em>Remark:</em> The second constructor shall not participate in overload resolution unless <code>Y*</code> is <del>convertible to</del> <ins> <em>compatible with</em> </ins> <code>T*</code>.</p>

<p>-20- <em>Effects:</em> [...]</p>

<p>-21- <em>Postconditions:</em> [...]</p>

<pre><code>  template&lt;class Y&gt; explicit shared_ptr(const weak_ptr&lt;Y&gt;&amp; r);
</code></pre>

<p>-22-
<em>Requires:</em> <code>Y*</code> shall be <del>convertible to</del> <ins> <em>compatible with</em> </ins> <code>T*</code>.</p>

<p>-23- <em>Effects:</em> [...]</p>

<p>-24- <em>Postconditions:</em> [...]</p>

<p>-25- <em>Throws:</em> [...]</p>

<pre><code>  template &lt;class Y, class D&gt; shared_ptr(unique_ptr&lt;Y, D&gt;&amp;&amp; r);
</code></pre>

<p>-26-
<em>Remark:</em> This constructor shall not participate in overload resolution unless <code>unique_ptr&lt;Y, D&gt;::pointer</code> is <del>convertible to</del> <ins> <em>compatible with</em> </ins> <code>T*</code>.</p>

<p>-27 <em>Effects:</em> [...]</p></blockquote>

<p>Change 20.10.2.2.5 <code>shared_ptr</code> observers [util.smartptr.shared.obs]:</p>

<blockquote><pre><code>  <del>T</del><ins>element_type</ins>* get() const noexcept;
</code></pre>

<p>-1-
<em>Returns:</em> the stored pointer.</p>

<pre><code>  T&amp; operator*() const noexcept;
</code></pre>

<p>-2-
<em>Requires:</em> <code>get() != 0</code>.</p>

<p>-3-
<em>Returns:</em> <code>*get()</code>.</p>

<p>-4-
<em>Remarks:</em> When <code>T</code> is <ins> an array type or </ins> (possibly cv-qualified) <code>void</code>, it is unspecified whether this member function is declared.
If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.</p>

<pre><code>  T* operator-&gt;() const noexcept;
</code></pre>

<p>-5-
<em>Requires:</em> <code>get() != 0</code>.</p>

<p>-6-
<em>Returns:</em> <code>get()</code>.</p>

<p><ins> -?- <em>Remarks:</em>
When <code>T</code> is an array type, it is unspecified whether this member function is declared.
If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed. </ins></p>

<pre><code>  <ins>element_type&amp; operator[](ptrdiff_t i) const;</ins>
</code></pre>

<p><ins> -?- <em>Requires:</em> <code>get() != 0 &amp;&amp; i &gt;= 0</code>. If <code>T</code> is <code>U[N]</code>, <code>i &lt; N</code>. </ins></p>

<p><ins> -?- <em>Returns:</em> <code>get()[i]</code>. </ins></p>

<p><ins> -?- <em>Remarks:</em>
When <code>T</code> is not an array type, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.
</ins></p>

<p><ins> -?- <em>Throws:</em> Nothing.
</ins></p></blockquote>

<p>Change 20.10.2.2.9 <code>shared_ptr</code> casts [util.smartptr.shared.cast]:</p>

<blockquote><pre><code>  template&lt;class T, class U&gt; shared_ptr&lt;T&gt; static_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
</code></pre>

<p>-1-
<em>Requires:</em> The expression <code>static_cast&lt;T*&gt;(<del>r.get()</del><ins>(U*)0</ins>)</code> shall be well formed.</p>

<p>-2- <em>Returns:</em>
<ins> <code>shared_ptr&lt;T&gt;(r, static_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>. </ins>
<del> If <code>r</code> is empty, an empty <code>shared_ptr&lt;T&gt;</code>; otherwise, a <code>shared_ptr&lt;T&gt;</code> object that stores <code>static_cast&lt;T*&gt;(r.get())</code> and shares ownership with <code>r</code>. </del></p>

<p><del>
-3-
<em>Postconditions:</em> <code>w.get() == static_cast&lt;T*&gt;(r.get())</code> and <code>w.use_count() == r.use_count()</code>, where <code>w</code> is the return value. </del></p>

<p>-4-
[<em>Note:</em> 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. <em>--end note</em>]</p>

<pre><code>  template&lt;class T, class U&gt; shared_ptr&lt;T&gt; dynamic_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
</code></pre>

<p>-5-
<em>Requires:</em> The expression <code>dynamic_cast&lt;T*&gt;(<del>r.get()</del><ins>(U*)0</ins>)</code> shall be well formed and shall have well defined behavior.</p>

<p>-6-
<em>Returns:</em><br/>
 — When <code>dynamic_cast&lt;<del>T</del><ins>typename shared_ptr&lt;T&gt;::element_type</ins>*&gt;(r.get())</code> returns a nonzero value<del>, a <code>shared_ptr&lt;T&gt;</code> object that stores a copy of it and shares ownership with <code>r</code></del> <ins><code>p</code>, <code>shared_ptr&lt;T&gt;(r, p)</code></ins>;<br/>
 — Otherwise, <del>an empty</del> <code>shared_ptr&lt;T&gt;<ins>()</ins></code> <del>object</del>.
<ins> </ins></p>

<p><del> -7-
<em>Postcondition:</em> <code>w.get() == dynamic_cast&lt;T*&gt;(r.get())</code>, where <code>w</code> is the return value. </del></p>

<p>-8-
 [<em>Note:</em> The seemingly equivalent expression shared_ptr<T>(dynamic_cast&lt;T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. <em>--end note</em>]</p>

<pre><code>  template&lt;class T, class U&gt; shared_ptr&lt;T&gt; const_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;
</code></pre>

<p>-9-
<em>Requires:</em> The expression <code>const_cast&lt;T*&gt;(<del>r.get()</del><ins>(U*)0</ins>)</code> shall be well formed.</p>

<p>-10-
<em>Returns:</em>
<ins> <code>shared_ptr&lt;T&gt;(r, const_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>. </ins>
<del> If <code>r</code> is empty, an empty <code>shared_ptr&lt;T&gt;</code>; otherwise, a <code>shared_ptr&lt;T&gt;</code> object that stores <code>const_cast&lt;T*&gt;(r.get())</code> and shares ownership with <code>r</code>. </del></p>

<p><del> -11-
<em>Postconditions:</em> <code>w.get() == const_cast&lt;T*&gt;(r.get())</code> and <code>w.use_count() == r.use_count()</code>, where <code>w</code> is the return value. </del></p>

<p>-12-
 [<em>Note:</em> 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. <em>--end note</em>]</p>

<pre><code>  <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>
</code></pre>

<p><ins> -?-
<em>Requires:</em>
The expression <code>reinterpret_cast&lt;T*&gt;((U*)0)</code> shall be well formed. </ins></p>

<p><ins> -?-
<em>Returns:</em>
<code>shared_ptr&lt;T&gt;(r, reinterpret_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code>.  </ins></p></blockquote>

<p>Change 20.10.2.3.1 <code>weak_ptr</code> constructors [util.smartptr.weak.const]:</p>

<blockquote><pre><code>  weak_ptr(const weak_ptr&amp; r) noexcept;
  template&lt;class Y&gt; weak_ptr(const weak_ptr&lt;Y&gt;&amp; r) noexcept;
  template&lt;class Y&gt; weak_ptr(const shared_ptr&lt;Y&gt;&amp; r) noexcept;
</code></pre>

<p>-3-
<em>Remark:</em> The second and third constructors shall not participate in overload resolution unless <code>Y*</code> is <del>implicitly convertible to</del> <ins> <em>compatible with</em> </ins> <code>T*</code>.</p></blockquote>

<h2>Acknowledgments</h2>

<p>Thanks to Alisdair Meredith for his careful review which caught some accidental
discrepancies from P0220R1.</p>
</body></html>
