Document Number: P1020R0
Date: 2018-04-08
Project: Programming Language C++
Audience: Library Evolution Working Group
Author: Glen Joseph Fernandes
(glenjofe@gmail.com),
Peter Dimov
(pdimov@pdimov.com)
This paper proposes adding the smart pointer creation functions
allocate_shared_default_init
,
make_shared_default_init
, and
make_unique_default_init
that perform default initialization.
It is not uncommon for arrays of built-in types such as unsigned
char
or double
to be immediately initialized by the user in
their entirety after allocation. In these cases, the value initialization
performed by allocate_shared
, make_shared
, and
make_unique
is redundant and hurts performance, and a way to
choose default initialization is needed.
The Boost Smart Pointers
library has provided an implementation of this proposal since Boost 1.56
released in 2014. The Boost functions are named
allocate_shared_noinit
, make_shared_noinit
, and
make_unique_noinit
, and are in widespread use.
All changes are relative to N4741.
Insert into 23.10.2 [memory.syn] as follows:
template<class T, class... Args> unique_ptr<T> make_unique(Args&&... args); //T is not array
template<class T> unique_ptr<T> make_unique(size_t n); //T is U[]
template<class T, class... Args> unspecified make_unique(Args&&...) = delete; //T is U[N]
template<class T> unique_ptr<T> make_unique_default_init(); //T is not array
template<class T> unique_ptr<T> make_unique_default_init(size_t n); //T is U[]
template<class T, class... Args> unspecified make_unique_default_init(Args&&...) = delete; //T is U[N]
[…]
template<class T> shared_ptr<T> make_shared(const remove_extent_t<T>& u); //T is U[N]
template<class T> shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u); //T is U[N]
template<class T> shared_ptr<T> make_shared_default_init(); //T is not U[]
template<class T> shared_ptr<T> allocate_shared_default_init(const A& a); //T is not U[]
template<class T> shared_ptr<T> make_shared_default_init(size_t N); //T is U[]
template<class T> shared_ptr<T> allocate_shared_default_init(const A& a, size_t N); //T is U[]
Insert after 23.11.1.4 [unique.ptr.create] p5 as follows:
template<class T> unique_ptr<T> make_unique_default_init(); //T is not array
Remarks: This function shall not participate in overload resolution unless
T
is not an array.Returns:
unique_ptr<T>(new T)
.template<class T> unique_ptr<T> make_unique_default_init(size_t n); //T is U[]
Remarks: This function shall not participate in overload resolution unless
T
is an array of unknown bound.Returns:
unique_ptr<T>(new remove_extent_t<T>[n])
.template<class T, class... Args> unspecified make_unique_default_init(Args&&...) = delete; //T is U[N]
Remarks: This function shall not participate in overload resolution unless
T
is an array of known bound.
Change 23.11.3.6 [util.smartptr.shared.create] p1 as follows:
The common requirements that apply to all
make_shared
,andallocate_shared
,make_shared_default_init,
andallocate_shared_default_init
overloads, unless specified otherwise, are described below.template<class T, ...> shared_ptr<T> make_shared(args);
template<class T, class A, ...> shared_ptr<T> allocate_shared(const A& a, args);
template<class T, ...> shared_ptr<T> make_shared_default_init(args);
template<class T, class A, ...> shared_ptr<T> allocate_shared_default_init(const A& a, args);
Change 23.11.3.6 [util.smartptr.shared.create] p3 as follows:
Effects: Allocates memory for an object of typeT
(orU[N]
whenT
isU[]
, whereN
is determined fromargs
as specified by the concrete overload). The object is initialized fromargs
as specified by the concrete overload. Theallocate_shared
andallocate_shared_default_init
templates use a copy ofa
(rebound for an unspecifiedvalue_type
) to allocate memory. If an exception is thrown, the functions have no effect.
Insert after 23.11.3.6 [util.smartptr.shared.create] p7.7 as follows:
— When a (sub)object of non-array typeU
is specified to have no initial value,make_shared_default_init
andallocate_shared_default_init
shall initialize this (sub)object via the expression::new(pv) U
, wherepv
has typevoid*
and points to storage suitable to hold an object of typeU
.
Insert after 23.11.3.6 [util.smartptr.shared.create] p22 as follows:
template<class T> shared_ptr<T> make_shared_default_init(); //T is not U[]
template<class T, class A> shared_ptr<T> allocate_shared_default_init(const A& a); //T is not U[]Returns: A
shared_ptr
to an object of typeT
, where each array element has no initial value.Remarks: These overloads shall only participate in overload resolution when
T
is not of the formU[]
.[Example:
struct X { double data[1024]; };
shared_ptr<X> p = make_shared_default_init<X>();
//shared_ptr to a default-initialized X, with X::data left uninitialized
shared_ptr<double[1024]> q = make_shared_default_init<double[1024]>();
//shared_ptr to a default-initialized double[1024], with the elements left uninitialized
—end example]template<class T> shared_ptr<T> make_shared_default_init(size_t N); //T is U[]
template<class T, class A> shared_ptr<T> allocate_shared_default_init(const A& a, size_t N); //T is U[]Returns: A
shared_ptr
to an object of typeU[N]
, whereU
isremove_extent_t<T>
and each array element has no initial value.Remarks: These overloads shall only participate in overload resolution when
T
is of the formU[]
.[Example:
shared_ptr<double[]> p = make_shared_default_init<double[]>(1024);
//shared_ptr to a default-initialized double[1024], with the elements left uninitialized
—end example]