make_shared and allocate_shared

# make_shared and allocate_shared for arrays

Introduction
Synopsis
Free Functions
Example
History

## Introduction

Originally the Boost function templates `make_shared` and `allocate_shared` were for efficient allocation of single objects only. There was a need to have efficient, single, allocation of arrays. One criticism of shared_array was always the lack of a make_shared utility which ensures only a single allocation for an array.

The header files <boost/smart_ptr/make_shared_array.hpp> and <boost/smart_ptr/allocate_shared_array.hpp> provide new function templates, `make_shared` and `allocate_shared`, to address this need. `make_shared` uses the global operator `new` to allocate memory, whereas `allocate_shared` uses an user-supplied allocator, allowing finer control.

## Synopsis

    namespace boost {
        template<typename U> // U = T[]
        shared_ptr<U> make_shared(size_t size);

        template<typename U, typename A> // U = T[]
        shared_ptr<U> allocate_shared(const A& allocator, size_t size);

    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
        template<typename U, typename... Args> // U = T[]
        shared_ptr<U> make_shared(size_t size, Args&&... args);

        template<typename U, typename... Args> // U = T[N]
        shared_ptr<U> make_shared(Args&&... args);

        template<typename U, typename A, typename... Args> // U = T[]
        shared_ptr<U> allocate_shared(const A& allocator, size_t size, Args&&... args);

        template<typename U, typename A, typename... Args> // U = T[N]
        shared_ptr<U> allocate_shared(const A& allocator, Args&&... args);
    #endif

    #if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX)
        template<typename U, typename... Args> // U = T[N]
        shared_ptr<U> make_shared(const T (&list)[N]);

        template<typename U, typename... Args> // U = T[][N]
        shared_ptr<U> make_shared(size_t size, const T (&list)[N]);

        template<typename U, typename... Args> // U = T[M][N]
        shared_ptr<U> make_shared(const T (&list)[N]);

        template<typename U, typename A, typename... Args> // U = T[N]
        shared_ptr<T[> allocate_shared(const A& allocator, const T (&list)[N]);

        template<typename U, typename A, typename... Args> // U = T[][N]
        shared_ptr<U> allocate_shared(const A& allocator, size_t size, const T (&list)[N]);

        template<typename U, typename A, typename... Args> // U = T[M][N]
        shared_ptr<U> allocate_shared(const A& allocator, const T (&list)[N]);

    #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
        template<typename U, typename... Args> // U = T[]
        shared_ptr<U> make_shared(initializer_list<T> list);

        template<typename U, typename A, typename... Args> // U = T[]
        shared_ptr<U> allocate_shared(const A& allocator, initializer_list<T> list);
    #endif

    #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
        template<typename U> // U = T[]
        shared_ptr<U> make_shared(size_t size, T&& value);

        template<typename U> // U = T[N]
        shared_ptr<U> make_shared(T&& value);

        template<typename U, typename A> // U = T[]
        shared_ptr<U> allocate_shared(const A& allocator, size_t size, T&& value);

        template<typename U, typename A> // U = T[N]
        shared_ptr<U> allocate_shared(const A& allocator, T&& value);
    #endif
    #endif

        template<typename U> // U = T[]
        shared_ptr<U> make_shared_noinit(size_t size);

        template<typename U> // U = T[N]
        shared_ptr<U> make_shared_noinit();

        template<typename U, typename A> // U = T[]
        shared_ptr<U> allocate_shared_noinit(const A& allocator, size_t size);

        template<typename U, typename A> // U = T[N]
        shared_ptr<U> allocate_shared_noinit(const A& allocator);
    }

## Free Functions

    template<typename U, typename... Args> // U = T[]
    shared_ptr<U> make_shared(size_t size, Args&&... args);

    template<typename U, typename A, typename... Args> // U = T[]
    shared_ptr<U> allocate_shared(const A& allocator, size_t size, Args&&... args);

> Requires: The expression `new(pointer) T(forward<Args>(args)...)`, where `pointer` is a `void*` pointing to storage suitable to hold an object of type `T`, shall be well-formed. `A` shall be an Allocator, as described in section 20.1.5 (Allocator requirements) of the C++ Standard. The copy constructor and destructor of `A` shall not throw.

> Effects: Allocates memory suitable for an array of type `T` and size `size` and constructs an array of objects in it via the placement new expression `new(pointer) T()` or `new(pointer) T(args...)`. `allocate_shared` uses a copy of `allocator` to allocate memory. If an exception is thrown, has no effect.

> Returns: A `shared_ptr` instance that stores and owns the address of the newly constructed array of type `T` and size `size`.

> Postconditions: `get() != 0 && use_count() == 1`.

> Throws: `bad_alloc`, or an exception thrown from `A::allocate` or the constructor of `T`.

> Notes: This implementation allocates the memory required for the returned `shared_ptr` and an array of type `T` of size `size` in a single allocation. This provides efficiency to equivalent to an intrusive smart array pointer.

> The prototypes shown above are used if your compiler supports r-value references and variadic templates. They perfectly forward the `args` parameters to the constructors of `T` for each array element.

> Otherwise, you can use the overloads which take only the array size (and the allocator in case of `allocate_shared`) and do not take any constructor arguments. These overloads invoke the default constructor of `T` for each array element.

    template<typename U, typename... Args> // U = T[N]
    shared_ptr<U> make_shared(Args&&... args);

    template<typename U, typename A, typename... Args> // U = T[N]
    shared_ptr<U> allocate_shared(const A& allocator, Args&&... args);

> Description: These overloads of the utilities above are for a fixed size array.

    template<typename U, typename... Args> // U = T[]
    shared_ptr<U> make_shared(initializer_list<T> list);

    template<typename U, typename A, typename... Args> // U = T[]
    shared_ptr<U> allocate_shared(const A& allocator, initializer_list<T> list);

> Description: These overloads initialize the array elements from the initializer list.

    template<typename U, typename... Args> // U = T[N]
    shared_ptr<U> make_shared(const T (&list)[N]);

    template<typename U, typename A, typename... Args> // U = T[N]
    shared_ptr<U> allocate_shared(const A& allocator, const T (&list)[N]);

> Description: These overloads of the utilities above are for a fixed size array.

    template<typename U, typename... Args> // U = T[][N]
    shared_ptr<U> make_shared(size_t size, const T (&list)[N]);

    template<typename U, typename A, typename... Args> // U = T[][N]
    shared_ptr<U> allocate_shared(const A& allocator, size_t size, const T (&list)[N]);

> Description: These overloads initialize inner array elements from the initializer list.

    template<typename U, typename... Args> // U = T[M][N]
    shared_ptr<U> make_shared(const T (&list)[N]);

    template<typename U, typename A, typename... Args> // U = T[M][N]
    shared_ptr<U> allocate_shared(const A& allocator, const T (&list)[N]);

> Description: These overloads of the utilities above are for a fixed size array.

    template<typename U> // U = T[]
    shared_ptr<U> make_shared(size_t size, T&& value);

    template<typename U, typename A> // U = T[]
    shared_ptr<U> allocate_shared(const A& allocator, size_t size, T&& value);

> Description: These overloads initialize array elements with the given value.

    template<typename U> // U = T[N]
    shared_ptr<U> make_shared(T&& value);

    template<typename U, typename A> // U = T[N]
    shared_ptr<U> allocate_shared(const A& allocator, T&& value);

> Description: These overloads of the utilities above are for a fixed size array.

    template<typename U> // U = T[]
    shared_ptr<U> make_shared_noinit(size_t size);

    template<typename U, typename A> // U = T[]
    shared_ptr<U> allocate_shared_noinit(const A& allocator, size_t size);

> Description: These overloads do not perform any value initialization of elements.

    template<typename U> // U = T[N]
    shared_ptr<U> make_shared_noinit();

    template<typename U, typename A> // U = T[N]
    shared_ptr<U> allocate_shared_noinit(const A& allocator);

> Description: These overloads of the utilities above are for a fixed size array.

## Example

An example of each overload of make_shared for arrays:

>     boost::shared_ptr<int[]> a1 = boost::make_shared<int[]>(size);
>     boost::shared_ptr<point[]> a2 = boost::make_shared<point[]>(size, x, y);
>     boost::shared_ptr<point[5]> a3 = boost::make_shared<point[5]>(x, y);
>     boost::shared_ptr<int[]> a4 = boost::make_shared<int[]>({1, 2, 3});
>     boost::shared_ptr<int[3]> a5 = boost::make_shared<int[3]>({1, 2, 3});
>     boost::shared_ptr<int[][3]> a6 = boost::make_shared<int[][3]>(size, {1, 2, 3});
>     boost::shared_ptr<int[5][3]> a7 = boost::make_shared<int[5][3]>({1, 2, 3});
>     boost::shared_ptr<point[]> a8 = boost::make_shared<point[]>(size, {x, y});
>     boost::shared_ptr<point[5]> a9 = boost::make_shared<point[5]>({x, y});
>     boost::shared_ptr<int[]> a10 = boost::make_shared_noinit<int[]>(size);
>     boost::shared_ptr<int[5]> a11 = boost::make_shared_noinit<int[5]>();

## History

November 2012. Glen Fernandes contributed implementations of make_shared and allocate_shared for arrays.

$Date: 2012-10-30 10:12:25 -0800 (Tue, 30 Oct 2012) $

Copyright 2012 Glen Fernandes. Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.