<html>
<head>
    <title>Extending shared_ptr to Support Arrays, Revision 2</title>
    <style type="text/css">
        ins { background-color: #A0FFA0; }
        del { background-color: #FFA0A0; }
    </style>
</head>
<body>
    <address>
        Document Number: N3920</address>
    <address>
        Programming Language C++</address>
    <address>
        Library Working Group</address>
    <address>
        &nbsp;</address>
    <address>
        Peter Dimov, &lt;<a href="mailto:pdimov@pdimov.com">pdimov@pdimov.com</a>&gt;</address>
    <address>
        &nbsp;</address>
    <address>
        2014-02-13</address>
    <h1>
        Extending shared_ptr to Support Arrays, Revision 2</h1>
    <p>
        This paper proposes adding array support to <code>shared_ptr</code>, via the syntax
        <code>shared_ptr&lt;T[]&gt;</code> and <code>shared_ptr&lt;T[N]&gt;</code>.</p>
    <h2>
        Changes in Revision 2</h2>
    <p>
        Incorporated wording suggestions from LEWG and LWG.</p>
    <h2>
        Changes in Revision 1</h2>
    <p>
        Incorporated wording suggestions from Daniel Krgler.</p>
    <h2>
        Motivation</h2>
    <p>
        Currently, if an apropriate deleter is used, <code>std::shared_ptr</code> can hold
        a pointer to an array allocated with <code>new[]</code>, but it doesn't offer direct
        support for that in the interface. This is an obvious omission, an inconsistency
        with <code>std::unique_ptr</code>, and even the subject of a national body comment
        (US 105). This paper suggests we take the steps to rectify this unfortunate situation,
        by making <code>shared_ptr&lt;T[]&gt;</code> and <code>shared_ptr&lt;T[N]&gt;</code>
        work as expected.</p>
    <p>
        The proposed changes have been implemented in Boost release 1.53, available from
        <a href="http://www.boost.org">www.boost.org</a>. The Boost distribution contains tests
        and documentation, which can be browsed <a href="http://www.boost.org/doc/libs/1_53_0/libs/smart_ptr/shared_ptr.htm">online</a>.</p>
    <p>
        <code>boost::make_shared</code> has also been extended to support arrays. The changes
        herein are a necessary prerequisite for the <code>make_shared</code> extensions,
        which are a subject of a separate paper (N3870).</p>
    <h2>
        Complexity</h2>
    <p>
        Due to the way <code>shared_ptr</code> and <code>weak_ptr</code> are specified and implemented,
        they already contain most of the functionality that is required, so the changes are relatively
        minor and local in both cases. The underlying semantics are already present, as <code>shared_ptr</code>
        can already hold pointers to arrays via an appropriate deleter. In addition, its behavior does not
        generally depend on the template parameter <code>T</code>, which is why most of the code and wording
        does not mind dealing with <code>T = U[]</code> or <code>U[N]</code>.</p>
    <p>
        It should also be noted that <code>shared_ptr&lt;Y&gt;</code> is convertible to <code>shared_ptr&lt;T&gt;</code>
        when <code>Y*</code> is convertible to <code>T*</code> and that it so happens that the core language cooperates
        very well with us in this case by making pointers to array types convertible only via qualification conversions,
        which is exactly what we want.</p>
    <p>
        The unfortunate occurence of <code>unique_ptr</code> having lost its support for <code>U[N]</code> obliges me to
        assert that in <code>shared_ptr</code> case, said support is essentially free, both in terms of implementation
        complexity or specification complexity. Please don't remove it. Consider reinstating <code>unique_ptr&lt;U[N]&gt;</code>
        instead.</p>
    <h2>
        reinterpret_pointer_cast</h2>
    <p>
        The proposed text suggests the addition of <code>reinterpret_pointer_cast</code>, to match the other casts and complete
        the family. It's useful when dealing with arrays of layout-compatible types, but is not essential for the proposal.
        It could be sacrificed if necessary.</p>
    <h2>
        Proposed Text</h2>
    <p>
        <em>(All edits are relative to N3485.)</em></p>
    <p>
        Add the following to the <code>&lt;memory&gt;</code> synopsis in 20.6.2 [memory.syn]:</p>
    <blockquote>
    <pre><em>// 20.7.2.2.9, shared_ptr casts:</em>
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; static_pointer_cast(shared_ptr&lt;U&gt; const&amp; r) noexcept;
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; dynamic_pointer_cast(shared_ptr&lt;U&gt; const&amp; r) noexcept;
template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; const_pointer_cast(shared_ptr&lt;U&gt; const&amp; r) noexcept;
<ins>template&lt;class T, class U&gt;
shared_ptr&lt;T&gt; reinterpret_pointer_cast(shared_ptr&lt;U&gt; const&amp; r) noexcept;</ins></pre>
    </blockquote>
    <p>
        Make the following change to 20.7.2.2 [util.smartptr.shared]:</p>
    <blockquote><pre>public:
  typedef <del>T</del> <ins>typename remove_extent&lt;T&gt;::type</ins> element_type;</pre>
    </blockquote>
    <p>
        Make the following change to 20.7.2.2 [util.smartptr.shared]:</p>
    <blockquote><pre>template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r, <del>T</del> <ins>element_type</ins> *p) noexcept;</pre>
    </blockquote>
    <p>
        Make the following change to 20.7.2.2 [util.smartptr.shared]:</p>
    <blockquote><pre><em>// 20.7.2.2.5, observers:</em>
<del>T*</del> <ins>element_type*</ins> get() const noexcept;
T&amp; operator*() const noexcept;
T* operator->() const noexcept;
<ins>element_type&amp; operator[](ptrdiff_t i) const noexcept;</ins></pre>
    </blockquote>
    <p>
        Make the following change to 20.7.2.2 [util.smartptr.shared] p1:</p>
    <blockquote><pre><em>// 20.7.2.2.9, shared_ptr casts:</em>
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;
shared_ptr&lt;T&gt; reinterpret_pointer_cast(const shared_ptr&lt;U&gt;&amp; r) noexcept;</ins></pre>
    </blockquote>
    <p>
        Change 20.7.2.2 [util.smartptr.shared] p2 as follows:</p>
    <blockquote>Specializations of <code>shared_ptr</code> shall be <code>CopyConstructible</code>,
    <code>CopyAssignable</code>, and <code>LessThanComparable</code>, allowing their use in standard
    containers. Specializations of <code>shared_ptr</code> shall be <ins>contextually </ins>convertible to <code>bool</code>,
    allowing their use in boolean expressions and declarations in conditions. The template parameter <code>T</code> of
    <code>shared_ptr</code> may be an incomplete type.
    </blockquote>
    <p>
        Add a new paragraph to 20.7.2.2 [util.smartptr.shared] after p4:</p>
    <blockquote><ins>For the purposes of subclause 20.7.2 [util.smartptr], 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 <em>cv</em> []</code>.</ins>
    </blockquote>
    <p>
        Change 20.7.2.2.1 [util.smartptr.shared.const] p3, p4, p7 as follows:</p>
    <blockquote><pre>template&lt;class Y&gt; explicit shared_ptr(Y* p);</pre>
        <blockquote><em>Requires:</em> <del><code>p</code> shall be convertible to <code>T*</code>. <code>Y</code> shall be a complete type. The expression <code>delete p</code> shall be
        well formed, shall have well defined behavior, and shall not throw exceptions.</del>
        <ins><code>Y</code> shall be a complete type. The expression <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,
        shall be well-formed, shall have well defined behavior, and shall not throw exceptions. 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></blockquote>
        <blockquote><em>Effects:</em> <ins>When <code>T</code> is not an array type, c</ins><del>C</del>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 <em>owns</em> <code>p</code> and a deleter of an unspecified type that calls <code>delete[] p</code>.</ins></blockquote>
        <blockquote><em>Posconditions:</em> <code>use_count() == 1 &amp;&amp; get() == p</code>.</blockquote>
        <blockquote><em>Throws:</em> <code>bad_alloc</code>, or an implementation-defined exception when a resource other than memory could not be obtained.</blockquote>
        <blockquote><em>Exception safety:</em> 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>.</blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.1 [util.smartptr.shared.const] p8 as follows:</p>
    <blockquote><pre>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);</pre>
        <blockquote><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></blockquote>
    </blockquote>
    <p>
        Change the line between 20.7.2.2.1 [util.smartptr.shared.const] p12 and p13 as follows:</p>
    <blockquote><pre>template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r, <del>T</del> <ins>element_type</ins> *p) noexcept;</pre></blockquote>
    <p>
        Change 20.7.2.2.1 [util.smartptr.shared.const] p17 as follows:</p>
    <blockquote><pre>shared_ptr(const shared_ptr&amp; r) noexcept;
template&lt;class Y&gt; shared_ptr(const shared_ptr&lt;Y&gt;&amp; r) noexcept;</pre>
        <blockquote><em>Requires:</em> The second constructor shall not participate in the overload resolution unless <code>Y*</code> is
        <del>implicitly convertible to</del> <ins><em>compatible with</em></ins> <code>T*</code>.</blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.1 [util.smartptr.shared.const] p20 as follows:</p>
    <blockquote><pre>shared_ptr(shared_ptr&amp;&amp; r) noexcept;
template&lt;class Y&gt; shared_ptr(shared_ptr&lt;Y&gt;&amp;&amp; r) noexcept;</pre>
        <blockquote><em>Requires:</em> The second constructor shall not participate in the overload resolution unless <code>Y*</code> is
        <del>implicitly convertible to</del> <ins><em>compatible with</em></ins> <code>T*</code>.</blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.1 [util.smartptr.shared.const] p23 as follows:</p>
    <blockquote><pre>template&lt;class Y&gt; explicit shared_ptr(const weak_ptr&lt;Y&gt;&amp; r);</pre>
        <blockquote><em>Requires:</em> <code>Y*</code> shall be <del>convertible to</del> <ins><em>compatible with</em></ins> <code>T*</code>.</blockquote>
    </blockquote>
    <p>
        Add a new paragraph before 20.7.2.2.1 [util.smartptr.shared.const] p33:</p>
    <blockquote><pre>template &lt;class Y, class D&gt; shared_ptr(unique_ptr&lt;Y, D&gt;&amp;&amp;r);</pre>
        <blockquote><ins><em>Requires:</em> <code>Y*</code> shall be <em>compatible with</em> <code>T*</code>.</ins></blockquote>
        <blockquote><em>Effects:</em> Equivalent to <code>shared_ptr(r.release(), r.get_deleter())</code> when <code>D</code> is not a reference type,
            otherwise <code>shared_ptr(r.release(), ref(r.get_deleter()))</code>.</blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.5 [util.smartptr.shared.obs] p1-p6 and the preceding line as follows:</p>
    <blockquote><pre><del>T*</del> <ins>element_type*</ins> get() const noexcept;</pre>
        <blockquote><em>Returns:</em> the stored pointer.</blockquote>
    </blockquote>
    <blockquote><pre>T&amp; operator*() const noexcept;</pre>
        <blockquote><em>Requires:</em> <code>get() != 0</code>.</blockquote>
        <blockquote><em>Returns:</em> <code>*get()</code>.</blockquote>
        <blockquote><em>Remarks:</em> When <code>T</code> is <ins>an array type or cv-qualified </ins><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.</blockquote>
    </blockquote>
    <blockquote><pre>T* operator-&gt;() const noexcept;</pre>
        <blockquote><em>Requires:</em> <code>get() != 0</code>.</blockquote>
        <blockquote><em>Returns:</em> <code>get()</code>.</blockquote>
        <blockquote><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></blockquote>
    </blockquote>
    <blockquote><pre><ins>element_type&amp; operator[](ptrdiff_t i) const noexcept;</ins></pre>
        <blockquote><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></blockquote>
        <blockquote><ins><em>Returns:</em> <code>get()[i]</code>.</ins></blockquote>
        <blockquote><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></blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.9 [util.smartptr.shared.cast] p1, p2, p3 as follows:</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;</pre>
        <blockquote><em>Requires:</em> The expression <del><code>static_cast&lt;T*&gt;(r.get())</code></del> <ins><code>static_cast&lt;T*&gt;((U*)0)</code></ins> shall be well formed.</blockquote>
        <blockquote><em>Returns:</em> <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> <ins><code>shared_ptr&lt;T&gt;(r, static_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code></ins>.</blockquote>
        <blockquote><del><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></blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.9 [util.smartptr.shared.cast] p5, p6, p7 as follows:</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;</pre>
        <blockquote><em>Requires:</em> The expression <del><code>dynamic_cast&lt;T*&gt;(r.get())</code></del> <ins><code>dynamic_cast&lt;T*&gt;((U*)0)</code></ins> shall be well formed<del> and shall have well defined behavior</del>.
            </blockquote>
        <blockquote><em>Effects:</em><ul><li>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<ins> <code>p</code></ins>,
            <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>shared_ptr&lt;T&gt;(r, p)</code></ins>;</li>
            <li>Otherwise, <del>an empty <code>shared_ptr&lt;T&gt;</code> object</del> <ins><code>shared_ptr&lt;T&gt;()</code></ins>.</li></ul></blockquote>
        <blockquote><del><em>Postconditions:</em> <code>w.get() == dynamic_cast&lt;T*&gt;(r.get())</code>, where <code>w</code> is the return value.</del></blockquote>
    </blockquote>
    <p>
        Change 20.7.2.2.9 [util.smartptr.shared.cast] p9, p10, p11 as follows:</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;</pre>
        <blockquote><em>Requires:</em> The expression <del><code>const_cast&lt;T*&gt;(r.get())</code></del> <ins><code>const_cast&lt;T*&gt;((U*)0)</code></ins> shall be well formed.</blockquote>
        <blockquote><em>Returns:</em> <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> <ins><code>shared_ptr&lt;T&gt;(r, const_cast&lt;typename shared_ptr&lt;T&gt;::element_type*&gt;(r.get()))</code></ins>.</blockquote>
        <blockquote><del><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></blockquote>
    </blockquote>
    <p>
        Add the following after 20.7.2.2.9 [util.smartptr.shared.cast] p12:</p>
    <blockquote><pre><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></pre>
        <blockquote><ins><em>Requires:</em> The expression <code>reinterpret_cast&lt;T*&gt;((U*)0)</code> shall be well formed.</ins></blockquote>
        <blockquote><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></blockquote>
    </blockquote>
    <p>
        Make the following change to 20.7.2.3 [util.smartptr.weak] p1:</p>
    <blockquote><pre>public:
  typedef <del>T</del> <ins>typename remove_extent&lt;T&gt;::type</ins> element_type;</pre>
    </blockquote>
    <p>
        Change 20.7.2.3.1 [util.smartptr.weak.const] p3 as follows:</p>
    <blockquote><pre>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;</pre>
        <blockquote><em>Requires:</em> The second and third constructors shall not participate in the overload resolution unless <code>Y*</code> is
        <del>implicitly convertible to</del> <ins><em>compatible with</em></ins> <code>T*</code>.</blockquote>
    </blockquote>
    <hr />
    <p>
        <em>Thanks to Glen Fernandes, whose contribution of <code>boost::make_shared</code> for arrays prompted the <code>boost::shared_ptr</code> additions proposed herein.</em></p>
    <p>
        <em>Thanks to Daniel Krgler for reviewing an earlier revision of this paper and suggesting wording improvements.</em></p>
    <p>
        <em>Thanks to Jonathan Wakely for providing valuable feedback.</em></p>
    <p>
        <em>&mdash; end</em></p>
</body>
</html>
