<html>
<head>
    <title>Extending make_shared to Support Arrays, Revision 2</title>
    <style type="text/css">
        ins { background-color: #A0FFA0; }
        del { background-color: #FFA0A0; }
        .replace { background-color: #F0F0F0; }
    </style>
</head>
<body>
    <address>
        Document Number: N3939</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>
        Glen Fernandes, &lt;<a href="mailto:glenfe@live.com">glenfe@live.com</a>&gt;</address>
    <address>
        &nbsp;</address>
    <address>
        2014-02-17</address>
    <h1>
        Extending make_shared to Support Arrays, Revision 2</h1>
    <p>
        This paper proposes adding array support to <code>make_shared</code>, via the syntax
        <code>make_shared&lt;T[]&gt;</code> and <code>make_shared&lt;T[N]&gt;</code>.</p>
    <h2>
        Changes in Revision 2</h2>
    <p>
        This revision of N3870 removes the scalar <code>T&amp;&amp;</code> overloads, reflecting
        the result of the LEWG review.</p>
    <h2>
        Changes in Revision 1</h2>
    <p>
        This revision of N3641 significantly narrows the scope of the proposal, based on
        feedback from Jeffrey Yasskin and Stephan T. Lavavej. It cuts down the number
        of <code>make_shared</code> overloads considerably, leaving only two use cases:</p>
    <p>
        &mdash; Value initialization, analogous to <code>new U[N]()</code>:</p>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N); // T is U[]
template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(); // T is U[N]
</pre>
    </blockquote>
    <p>
        &mdash; Per-element initialization to a specified value, analogous to the
        <code>std::vector&lt;U&gt;(N, u)</code> constructor:</p>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N, const U&amp; u); // T is U[]
template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(const U&amp; u); // T is U[N]
</pre>
    </blockquote>
    <h2>
        Motivation</h2>
    <p>
        Programmers like <code>make_shared</code>. It delivers exception safety, is easier
        to type, and saves one allocation (and a few bytes in the control block). Not
        surprisingly, a very common request is for it to support arrays.</p>
    <p>
        Boost release 1.53, available from <a href="http://www.boost.org">www.boost.org</a>,
        contains an implementation of an earlier revision of this proposal (N3641). 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/make_shared_array.html">online</a>.</p>
    <p>
        The upcoming Boost release 1.56 will contain an implementation of this proposal,
        currently available from <a href="https://github.com/boostorg/smart_ptr/">Github</a>.</p>
    <p>
        A <code>shared_ptr</code> that supports arrays is a dependency that is the subject of
        a separate paper (N3920).</p>
    <p>
        The proposed wording also resolves library issue #2070.</p>
    <h2>
        Rationale</h2>
    <h3>
        <code>make_shared_noinit</code></h3>
    <p>
        It is not uncommon for arrays of built-in types such as <code>unsigned char</code>
        or <code>double</code> to be immediately initialized by the user in their entirety
        after allocation. In these cases, the value initialization performed by <code>make_shared</code>
        is redundant and hurts performance, and a way to choose default initialization is needed.</p>
    <p>
        This proposal suggests <code>make_shared_noinit</code> and <code>allocate_shared_noinit</code>
        as a way to perform default initialization on the elements. The suffix <code>_noinit</code>,
        instead of something derived from "default", has been chosen because the use cases
        of this overload always deal with either uninitialized elements (when the type is
        a built-in) or with potentially uninitialized elements (when the type is dependent
        on a template parameter in a generic function and may be a built-in). Typically,
        therefore, the programmer assumes that after <code>make_shared_noinit</code>, the
        elements are uninitialized, that is, hold unspecified values, and the <code>_noinit</code>
        name reflects this assumption.</p>
    <h2>
        Proposed Text</h2>
    <p>
        <em>(All edits are relative to N3485.)</em></p>
    <p>
        Change 20.7.2.2 [util.smartptr.shared] p1 as follows:</p>
    <blockquote><pre><em>// 20.7.2.2.6, shared_ptr creation</em>
template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args); <ins>// T is not array</ins>
template&lt;class T, class A, class... Args&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, Args&amp;&amp;... args); <ins>// T is not array</ins>

<ins>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N); // T is U[]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a); // T is U[N]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N, const U&amp; u); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N, const U&amp; u); // T is U[]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(const U&amp; u); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, const U&amp; u); // T is U[N]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(); // T is not U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a); // T is not U[]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(size_t N); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a, size_t N); // T is U[]</ins></pre>
    </blockquote>
    <p>
        Replace the contents 20.7.2.2.6 [util.smartptr.shared.create] with the following:</p>
    <div class="replace">
    <blockquote>
        The common requirements that apply to all <code>make_shared</code>, <code>allocate_shared</code>,
        <code>make_shared_noinit</code>, and <code>allocate_shared_noinit</code>
        overloads, unless specified otherwise, are described below.</blockquote>
    <blockquote><pre>template&lt;class T, <em>...</em>&gt; shared_ptr&lt;T&gt; make_shared(<em>args</em>);
template&lt;class T, class A, <em>...</em>&gt; shared_ptr&lt;T&gt; allocate_shared(const A&amp; a, <em>args</em>);
template&lt;class T, <em>...</em>&gt; shared_ptr&lt;T&gt; make_shared_noinit(<em>args</em>);
template&lt;class T, class A, <em>...</em>&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A&amp; a, <em>args</em>);</pre>
    <blockquote><em>Requires:</em> <code>A</code> shall be an <em>allocator</em> (17.6.3.5). The copy constructor
    and destructor of <code>A</code> shall not throw exceptions.</blockquote>
    <blockquote><em>Effects:</em> Allocates memory for an object of type <code>T</code> (or <code>U[N]</code> when
    <code>T</code> is <code>U[]</code>, where <code>N</code> is determined from <code><em>args</em></code> as specified by the concrete overload).
    The object is initialized from <code><em>args</em></code> as specified by the concrete overload. The templates <code>allocate_shared</code> and
    <code>allocate_shared_noinit</code> use a copy of <code>a</code> to allocate memory. If an exception is thrown, the functions have no effect.</blockquote>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> instance that stores and owns the address of the newly constructed object.</blockquote>
    <blockquote><em>Postconditions:</em> <code>r.get() != 0 &amp;&amp; r.use_count() == 1</code>, where <code>r</code> is the return value.</blockquote>
    <blockquote><em>Throws:</em> <code>bad_alloc</code>, an exception thrown from <code>A::allocate</code>, or from the initialization of the object.</blockquote>
    <blockquote><em>Remarks:</em>
        <blockquote>Implementations should perform no more than one memory allocation. [ <em>Note:</em> This provides
        efficiency equivalent to an intrusive smart pointer. <em>&mdash; end note</em> ].</blockquote>
        <blockquote>When an object of an array type <code>U</code> is specified to be initialized to a value of the same type <code>u</code>, this shall be
        interpreted to mean that each array element of the object is initialized to the corresponding element from <code>u</code>.</blockquote>
        <blockquote>When an object of an array type is specified to be value-initialized, this shall be interpreted to mean that each array element of the object
        is value-initialized.</blockquote>
        <blockquote>When a (sub)object of a non-array type <code>U</code> is specified to be initialized to a value <code>v</code>, or to <code>U(<em>l...</em>)</code>, where
        <code><em>l...</em></code> is a list of constructor arguments, <code>make_shared</code> shall perform this initialization via the expression
        <code>::new(pv) U(v)</code> or <code>::new(pv) U(<em>l...</em>)</code> respectively, where <code>pv</code> has type <code>void*</code> and
        points to storage suitable to hold an object of type <code>U</code>.</blockquote>
        <blockquote>When a (sub)object of non-array type <code>U</code> is specified to be initialized to a value <code>v</code>, or to <code>U(<em>l...</em>)</code>, where
        <code><em>l...</em></code> is a list of constructor arguments, <code>allocate_shared</code> shall perform this initialization via the expression
        <code>allocator_traits&lt;A2&gt;::construct(a2, pv, v)</code> or <code>allocator_traits&lt;A2&gt;::construct(a2, pv, <em>l...</em>)</code> respectively,
        where <code>pv</code> points to storage suitable to hold an object of type <code>U</code> and <code>a2</code> of type <code>A2</code> is a rebound
        copy of the allocator <code>a</code> passed to <code>allocate_shared</code> such that its <code>value_type</code> is <code>U</code>.</blockquote>
        <blockquote>When a (sub)object of non-array type <code>U</code> is specified to be value-initialized, <code>make_shared</code> shall perform this initialization via
        the expression <code>::new(pv) U()</code>, where <code>pv</code> has type <code>void*</code> and points to storage suitable to hold an object of type
        <code>U</code>.</blockquote>
        <blockquote>When a (sub)object of non-array type <code>U</code> is specified to be value-initialized, <code>allocate_shared</code> shall perform this initialization
        via the expression <code>allocator_traits&lt;A2&gt;::construct(a2, pv)</code>, where <code>pv</code> points to storage suitable to hold an object of type
        <code>U</code> and <code>a2</code> of type <code>A2</code> is a rebound copy of the allocator <code>a</code> passed to <code>allocate_shared</code> such that
        its <code>value_type</code> is <code>U</code>.</blockquote>
        <blockquote>When a (sub)object of non-array type <code>U</code> is specified to be default-initialized, <code>make_shared_noinit</code> and
        <code>allocate_shared_noinit</code> shall perform this initialization via the expression <code>::new(pv) U</code>, where <code>pv</code> has type
        <code>void*</code> and points to storage suitable to hold an object of type <code>U</code>.</blockquote>
        <blockquote>Array elements are initialized in ascending order of their addresses.</blockquote>
        <blockquote>When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception,
        the initialized elements should be destroyed in the reverse order of their construction.</blockquote>
    </blockquote>
    <blockquote>[ <em>Note:</em> These functions will typically allocate more memory than <code>sizeof(T)</code> to allow for internal
    bookkeeping structures such as the reference counts. <em>&mdash; end note</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args); // T is not array
template&lt;class T, class A, class... Args&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, Args&amp;&amp;... args); // T is not array</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>T</code>, initialized to
    <code>T(forward&lt;Args&gt;(args)...)</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is
    not an array type.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;int&gt; p = make_shared&lt;int&gt;(); // shared_ptr to int()</pre>
        <pre>  shared_ptr&lt;vector&lt;int&gt;&gt; q = make_shared&lt;vector&lt;int&gt;&gt;(16, 1); // shared_ptr to vector of 16 elements with value 1</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N); // T is U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to a value-initialized object of type <code>U[N]</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is of the form <code>U[]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;double[]&gt; p = make_shared&lt;double[]&gt;(1024); // shared_ptr to a value-initialized double[1024]</pre>
        <pre>  shared_ptr&lt;double[][2][2]&gt; q = make_shared&lt;double[][2][2]&gt;(6); // shared_ptr to a value-initialized double[6][2][2]</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a); // T is U[N]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to a value-initialized object of type <code>U[N]</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is of the form <code>U[N]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;double[1024]&gt; p = make_shared&lt;double[1024]&gt;(); // shared_ptr to a value-initialized double[1024]</pre>
        <pre>  shared_ptr&lt;double[6][2][2]&gt; q = make_shared&lt;double[6][2][2]&gt;(); // shared_ptr to a value-initialized double[6][2][2]</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(size_t N, const U&amp; u); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N, const U&amp; u); // T is U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N]</code>, where each array element of type <code>U</code> is initialized
        to <code>u</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is of the form <code>U[]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;double[]&gt; p = make_shared&lt;double[]&gt;(1024, 1.0); // shared_ptr to a double[1024], where each element is 1.0</pre>
        <pre>  shared_ptr&lt;double[][2]&gt; q = make_shared&lt;double[][2]&gt;(6, {1.0, 0.0}); // shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}</pre>
        <pre>  shared_ptr&lt;vector&lt;int&gt;[]&gt; r = make_shared&lt;vector&lt;int&gt;[]&gt;(4, {1, 2}); // shared_ptr to a vector&lt;int&gt;[4], where each vector has contents {1, 2}</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(const U&amp; u); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, const U&amp; u); // T is U[N]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N]</code>, where each array element of type <code>U</code> is initialized
        to <code>u</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is of the form <code>U[N]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;double[1024]&gt; p = make_shared&lt;double[1024]&gt;(1.0); // shared_ptr to a double[1024], where each element is 1.0</pre>
        <pre>  shared_ptr&lt;double[6][2]&gt; q = make_shared&lt;double[6][2]&gt;({1.0, 0.0}); // shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}</pre>
        <pre>  shared_ptr&lt;vector&lt;int&gt;[4]&gt; r = make_shared&lt;vector&lt;int&gt;[4]&gt;({1, 2}); // shared_ptr to a vector&lt;int&gt;[4], where each vector has contents {1, 2}</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(); // T is not U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a); // T is not U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to a default-initialized object of type <code>T</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is not of the form <code>U[]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  struct X { double data[1024]; };</pre>
        <pre>  shared_ptr&lt;X&gt; p = make_shared_noinit&lt;X&gt;(); // shared_ptr to a default-initialized X, with X::data left uninitialized</pre>
        <pre>  shared_ptr&lt;double[1024]&gt; q = make_shared_noinit&lt;double[1024]&gt;(); // shared_ptr to a default-initialized double[1024], with the elements left unitialized</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(size_t N); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a, size_t N); // T is U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to a default-initialized object of type <code>U[N]</code>.</blockquote>
    <blockquote><em>Remarks:</em> These overloads shall only participate in overload resolution when <code>T</code> is of the form <code>U[]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>  shared_ptr&lt;double[]&gt; p = make_shared_noinit&lt;double[]&gt;(1024); // shared_ptr to a default-initialized double[1024], with the elements left unitialized</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    </div>
    <hr />
    <p>
        <em>&mdash; end</em></p>
</body>
</html>
