<html>
<head>
    <title>Extending make_shared to Support Arrays</title>
    <style type="text/css">
        ins { background-color: #A0FFA0; }
        del { background-color: #FFA0A0; }
    </style>
</head>
<body>
    <address>
        Document Number: N3641</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>
        2013-05-02</address>
    <h1>
        Extending make_shared to Support Arrays</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>
        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>
        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/make_shared_array.html">online</a>.
        The Boost implementation is primarily the work of Glen Fernandes.</p>
    <p>
        A <code>shared_ptr</code> that supports arrays is a dependency that has been proposed
        in a separate paper (N3640).</p>
    <h2>
        Syntax</h2>
    <pre>shared_ptr&lt;T[]&gt; p = make_shared&lt;T[]&gt;(N);</pre>
    <pre>shared_ptr&lt;T[N]&gt; q = make_shared&lt;T[N]&gt;();</pre>
    <blockquote>
        Creates an array of <code>N</code> value-initialized elements of type <code>T</code>.</blockquote>
    <pre>shared_ptr&lt;T[][M]&gt; p = make_shared&lt;T[][M]&gt;(N);</pre>
    <pre>shared_ptr&lt;T[N][M]&gt; q = make_shared&lt;T[N][M]&gt;();</pre>
    <blockquote>
        Creates a two-dimensional array of <code>N*M</code> value-initialized elements of
        type <code>T</code>. More than two dimensions are supported as well.</blockquote>
    <pre>shared_ptr&lt;T[]&gt; p = make_shared&lt;T[]&gt;(N, a, b);</pre>
    <pre>shared_ptr&lt;T[N]&gt; q = make_shared&lt;T[N]&gt;(a, b);</pre>
    <blockquote>
        Creates an array of <code>N</code> elements of type <code>T</code>, each initialized
        to <code>T(a, b)</code>.</blockquote>
    <pre>shared_ptr&lt;T[][M]&gt; p = make_shared&lt;T[][M]&gt;(N, a, b);</pre>
    <pre>shared_ptr&lt;T[N][M]&gt; q = make_shared&lt;T[N][M]&gt;(a, b);</pre>
    <blockquote>
        Creates a two-dimensional array of <code>N*M</code> elements of type <code>T</code>,
        each initialized to <code>T(a, b)</code>. More than two dimensions are supported
        as well.</blockquote>
    <pre>shared_ptr&lt;T[]&gt; p = make_shared_noinit&lt;T[]&gt;(N);</pre>
    <pre>shared_ptr&lt;T[N]&gt; q = make_shared_noinit&lt;T[N]&gt;();</pre>
    <blockquote>
        Creates an array of <code>N</code> default-initialized elements of type <code>T</code>.
        Useful when <code>T</code> is a built-in type such as <code>double</code>. Multidimensional
        arrays are supported. The scalar version of <code>make_shared</code> is also extended
        to support this syntax.</blockquote>
    <pre>shared_ptr&lt;T[]&gt; p = make_shared&lt;T[]&gt;(N, {a, b});</pre>
    <pre>shared_ptr&lt;T[N]&gt; q = make_shared&lt;T[N]&gt;({a, b});</pre>
    <blockquote>
        Creates an array of <code>N</code> elements of type <code>T</code>, each initialized
        to <code>{a, b}</code>. Can be used whenever <code>T{a, b}</code> is valid, but
        is particularly useful when <code>T(a, b)</code> and <code>T{a, b}</code> mean different
        things, such as when <code>T</code> is an aggregate or a container. The scalar version
        of <code>make_shared</code> is also extended to support this syntax.</blockquote>
    <pre>shared_ptr&lt;int[][3]&gt; p = make_shared&lt;int[][3]&gt;(N, {1, 2, 3});</pre>
    <pre>shared_ptr&lt;int[N][3]&gt; q = make_shared&lt;int[N][3]&gt;({1, 2, 3});</pre>
    <blockquote>
        Creates an array of <code>N</code> elements of type <code>int[3]</code>, each initialized
        to <code>{1, 2, 3}</code>. Conceptually the same as the previous example, with
        <code>T = int[3]</code>.</blockquote>
    <pre>shared_ptr&lt;int[]&gt; p = make_shared&lt;int[]&gt;({1, 2, 3});</pre>
    <pre>shared_ptr&lt;int[3]&gt; q = make_shared&lt;int[3]&gt;({1, 2, 3});</pre>
    <blockquote>
        Creates an array of 3 elements of type <code>int</code>, initialized to 1, 2, 3 respectively.
        The array size is deduced in the first case, checked in the second.</blockquote>
    <pre>shared_ptr&lt;int[][3]&gt; p = make_shared&lt;int[][3]&gt;({{1, 2, 3}, {4, 5, 6}});</pre>
    <pre>shared_ptr&lt;int[2][3]&gt; q = make_shared&lt;int[2][3]&gt;({{1, 2, 3}, {4, 5, 6}});</pre>
    <blockquote>
        Creates an array of 2 elements of type <code>int[3]</code>, initialized to <code>{1, 2, 3}</code> and <code>{4, 5, 6}</code> respectively.
        The outermost array size is deduced in the first case, checked in the second. This is the same as the previous example, with <code>int</code>
        replaced with <code>int[3]</code>.</blockquote>
    <h2>
        Rationale</h2>
    <h3>
        Per-element construction with arguments</h3>
    <p>
        The expressions <code>make_shared&lt;X[4]&gt;()</code> and <code>make_shared&lt;X[]&gt;(4)</code>
        cannot simply use <code>new(pv) X[4]</code> to initialize the elements, even though
        only value initialization is required. When <code>X</code> has a destructor, the <code>new[]</code>
        expression inserts a hidden size prefix, so that the elements are shifted in memory
        and <code>pv</code> doesn't point to the first element of type <code>X</code>.</p>
    <p>
        This can be demonstrated by the following program:</p>
    <blockquote><pre>#include &lt;memory&gt;
#include &lt;iostream&gt;

struct X
{
    int v;

    X(): v(1) {}
    ~X() {}
};

int main()
{
    std::shared_ptr&lt;X[4]&gt; p = std::make_shared&lt;X[4]&gt;();

    for( int i = 0; i &lt; 4; ++i )
    {
        std::cout &lt;&lt; (*p)[i].v &lt;&lt; ' ';
    }

    std::cout &lt;&lt; std::endl;
}
</pre></blockquote>
    <p>
        Under one popular implementation, using the stock standard library, the above compiles and works,
        and produces the following output:</p>
    <blockquote><pre>4 1 1 1</pre></blockquote>
    <p>
        whereas, of course, one would expect</p>
    <blockquote><pre>1 1 1 1</pre></blockquote>
    <p>
        to be printed instead.</p>
    <p>
        For that reason, the implementation of <code>make_shared</code> for arrays needs to perform a loop
        and initialize the elements one by one, as in:</p>
    <blockquote><pre>for( int i = 0; i &lt; N; ++i )
{
    ::new( (void*)(px+i) ) X();
}
</pre></blockquote>
    <p>
        (with exception handling omitted for brevity.)</p>
    <p>
        With this loop in place, extending <code>make_shared</code> to support constructor arguments is obviously cost-free:</p>
    <blockquote><pre>for( int i = 0; i &lt; N; ++i )
{
    ::new( (void*)(px+i) ) X(<ins>args...</ins>);
}
</pre></blockquote>
    <p>
        This is why this proposal does not limit <code>make_shared</code> to value initialization.</p>
    <h3>
        Explicit support for multidimensional arrays</h3>
    <p>
        For the same reasons outlined in the previous section, the expression <code>make_shared&lt;Y[4][2]&gt;()</code>
        cannot use the loop</p>
    <blockquote><pre>for( int i = 0; i &lt; 4; ++i )
{
    ::new( (void*)(px+i) ) Y[2]();
}
</pre></blockquote>
    <p>
        for initialization, which is what will happen if the specification and the implementation
        do not take into account the possibility of the array element in <code>X[4]</code>
        being or an array type (<code>Y[2]</code>) itself.</p>
    <p>
        So, multidimensional arrays need to be addressed explicitly in the specification,
        one way or another. The two options are to either disallow them outright, or support
        them. This proposal chooses to fully support multidimensional arrays, by flattening
        the initialization loop. For the above example, the initialization would have the form:</p>
    <blockquote><pre>for( int i = 0; i &lt; 4*2; ++i )
{
    ::new( (void*)(py+i) ) Y();
}
</pre></blockquote>
    <h3>
        Per-element construction with an initializer list</h3>
    <p>
        Per-element construction using constructor arguments &mdash; <code>T(a, b)</code> &mdash; is enough
        for the majority of cases, but there are scenarios in which one would like to use
        <code>T{a, b}</code> instead. Aggregates, as one example, can only be initialized
        with <code>{}</code>; standard containers, as another, support both <code>T(a, b)</code>
        and <code>T{a, b}</code>, but give the two forms different meanings.</p>
    <p>
        This proposal suggests the syntax <code>make_shared&lt;T&gt;({a, b})</code>, <code>make_shared&lt;T[]&gt;(N,
            {a, b})</code> and <code>make_shared&lt;T[N]&gt;({a, b})</code> as a way to
        initialize elements with <code>T{a, b}</code> for the scalar case, array with an
        unknown bound case, and array with known bound case, respectively.</p>
    <p>
        If <code>Args&amp;&amp;... args</code> could take <code>{a, b}</code> and forward
        it perfectly, we wouldn't need another overload to support the above syntax. It
        cannot, so we do. Its implementation is essentially the same as that of the <code>Args</code>
        overload; the only difference is that it takes an argument of type <code>remove_all_extents&lt;T&gt;::type&amp;&amp;</code>
        and passes it to the constructor instead of <code>args...</code></p>
    <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 build-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 uinitialized, that is, hold unspecified values, and the <code>_noinit</code>
        name reflects this assumption.</p>
    <h3>
        Whole array construction with an initializer list</h3>
    <p>
        The motivation for providing a way to initialize an entire array from given values
        comes from the scalar case. Consider the following example, which is supported:</p>
    <blockquote><pre>struct X { int v[3][2]; };

make_shared&lt;X&gt;( {{1, 2}, {3, 4}, {5, 6}} );
</pre></blockquote>
    <p>
        and now compare with its equivalent without the wrapper struct:</p>
    <blockquote><pre>make_shared&lt;int[3][2]&gt;( {{1, 2}, {3, 4}, {5, 6}} );</pre></blockquote>
    <p>
        Clearly, it makes sense for the latter to be supported, since the former is.</p>
    <h3>
        Array construction with a repeated initializer list</h3>
    <p>
        Finally, consider the following supported example:</p>
    <blockquote><pre>struct X { double a, b; };

make_shared&lt;X[]&gt;( 1024, {1.0, 0.0} );
</pre></blockquote>
    <p>
        and its two-dimensional array equivalent:</p>
    <blockquote><pre>make_shared&lt;double[][2]&gt;( 1024, {1.0, 0.0} );</pre></blockquote>
    <p>
        Here it also makes perfect sense by analogy for the latter to be supported, since
        the former is.</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(T&amp;&amp; t); // T is not array
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, T&amp;&amp; t); // T is not array

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

template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(Args&amp;&amp;... args); // T is U[N]
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 U[N]

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

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // T is U[N]

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

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

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

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

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

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[]

template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a); // T is U[N]</ins></pre>
    </blockquote>
    <p>
        Replace the contents 20.7.2.2.6 [util.smartptr.shared.create] with the following:</p>
    <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 a (sub)object of 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 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 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;vector&lt;int&gt;&gt; p = 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(T&amp;&amp; t); // T is not array
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, T&amp;&amp; t); // 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>move(t)</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;pair&lt;string,int&gt;&gt; p = make_shared&lt;pair&lt;string,int&gt;&gt;({"test",2}); // shared_ptr to pair{"test",2}</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 with contents {16,1}</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T, class... Args&gt; shared_ptr&lt;T&gt; make_shared(size_t N, Args&amp;&amp;... args); // T is U[]
template&lt;class T, class A, class... Args&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N, Args&amp;&amp;... args); // T is U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N]</code>, where each innermost array element of type
    <code>E == remove_all_extents&lt;T&gt;::type</code> is initialized to <code>E(forward&lt;Args&gt;(args)...)</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 double is 1.0</pre>
        <pre>shared_ptr&lt;double[][2][2]&gt; q = make_shared&lt;double[][2][2]&gt;(6, 1.0); // shared_ptr to a double[6][2][2], where each double is 1.0</pre>
        <em>&mdash; end example</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 U[N]
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 U[N]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>T</code>, where each innermost array element of type
    <code>E == remove_all_extents&lt;T&gt;::type</code> is initialized to <code>E(forward&lt;Args&gt;(args)...)</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 double is 1.0</pre>
        <pre>shared_ptr&lt;double[6][2][2]&gt; q = make_shared&lt;double[6][2][2]&gt;(1.0); // shared_ptr to a double[6][2][2], where each double is 1.0</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, typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N, typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // T is U[]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N]</code>, where each innermost array element of type
    <code>E == remove_all_extents&lt;T&gt;::type</code> is initialized to <code>e</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;vector&lt;int&gt;[]&gt; p = 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(typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, typename remove_all_extents&lt;T&gt;::type&amp;&amp; e); // 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 innermost array element of type
    <code>E == remove_all_extents&lt;T&gt;::type</code> is initialized to <code>e</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;vector&lt;int&gt;[4]&gt; p = 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(initializer_list&lt;U&gt; list); // T is U[]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, initializer_list&lt;U&gt; list); // 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 the corresponding element from <code>list</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;int[]&gt; p = make_shared&lt;int[]&gt;({1,2,3,4,5,6}); // shared_ptr to an int[6] with contents {1,2,3,4,5,6}</pre>
        <em>&mdash; end example</em> ].</blockquote>
    </blockquote>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared(const T&amp; list); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, const T&amp; list); // T is U[N]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>T</code> initialized from <code>list</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;int[6]&gt; p = make_shared&lt;int[6]&gt;({1,2,3,4,5,6}); // shared_ptr to an int[6] with contents {1,2,3,4,5,6}</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;list)[M]); // T is U[][M]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, size_t N, const U (&amp;list)[M]); // T is U[][M]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N][M]</code>, where each array element of type
    <code>U[M]</code> is initialized to <code>list</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;int[][2]&gt; p = make_shared&lt;int[][2]&gt;(16,{1,2}); // shared_ptr to an int[16][2], each int[2] subarray having 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;list)[M]); // T is U[N][M]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared(const A& a, const U (&amp;list)[M]); // T is U[N][M]</pre>
    <blockquote><em>Returns:</em> A <code>shared_ptr</code> to an object of type <code>U[N][M]</code>, where each array element of type
    <code>U[M]</code> is initialized to <code>list</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;int[16][2]&gt; p = make_shared&lt;int[16][2]&gt;({1,2}); // shared_ptr to an int[16][2], each int[2] subarray having 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 array
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a); // T is not array</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 an array type.</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>
        <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>
    <blockquote><pre>template&lt;class T&gt; shared_ptr&lt;T&gt; make_shared_noinit(); // T is U[N]
template&lt;class T, class A&gt; shared_ptr&lt;T&gt; allocate_shared_noinit(const A& a); // T is U[N]</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 of the form <code>U[N]</code>.</blockquote>
    <blockquote>[ <em>Example:</em>
        <pre>shared_ptr&lt;double[1024]&gt; p = 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>
    <hr />
    <p>
        <em>Thanks to Glen Fernandes, who implemented <code>boost::make_shared</code> for arrays.</em></p>
    <p>
        <em>&mdash; end</em></p>
</body>
</html>
