Document number: | P1978R0 | |
---|---|---|
Authors: | Andrzej Krzemieński Glen Joseph Fernandes Nevin Liber Peter Dimov |
|
Date: | 2019-11-15 | |
Audience: | Library Evolution Working Group | |
Reply-to: | Andrzej Krzemieński <akrzemi1 at gmail dot com>Glen Joseph Fernandes <glenjofe at gmail dot com> |
_default_init
functions and do nothing moreWhile addressing national body comment DE002, LEWG came up with the solution that went beyond changing function names (as requested in DE002), but also changed the design of these functions by applying constrains which renders these functions very difficult to use in generic contexts. In this paper we propose a smaller solution that is more in line with DE002, and that does not attempt to do a last-minute redesign.
The problem reported in DE002 is that functions that are meant to perform default initialization of heap-allocated objects are spelled like
make_unique_default_init
, which may mislead non-expert programmers — who do not understand terms from the Standard like "default initialization" —
to believe that objects will be initialized to their safe default values (which experst call "value initialization").
In response to that, P1973R0
changes the names to make_unique_uninitilized
, which now confuses a different group of non-experts, by incorrectly implying that these objects
are uninitialized. In order to avoid this new confusion, P1973R0 additionally proposes SFINAE-like constrains that make these functions available only
for types that are trivially default-constructible, which only partially mitigates the new confusion, but also makes these functions very difficult to use inside
templates.
Here is an example that now becomes difficult to write:
template <typename T, size_t Size> std::unique_ptr<T[]> initialize_array() { auto result = std::make_unique_default_init<T[]>(Size); for (size_t i = 0; i != Size; ++i) result[i] = produce_value<T>(i); return result; }
We first need to allocate the array, and only then fill it with meaningful values, so the initial values are never read. We want to perform this initialization
as fast as we can for every T
. This means that for types with user-provided default constructor we have to call this constructor, but for trivial types
we do the trivial initialization. With the solution proposed in P1973R0, writing this template is not that easy anymore. We have to either provide a specialisation
or use an if constexpr
to distinguish the two cases. The soluiton in P1973R0 seems to be missing the point of introducing these functions in the first place,
and disregarding this idiomatic use. This, in turn, impedes the migration from boost::make_unique_noinit
.
In the light of the above, we propose, as per DE002, to only change the names of these functions to make_unique_minimal_init
, and refrain from any other design changes.
Term "minimal" seems to be conveying the idea behind the idiom on the one hand, and on the other not to overlap with any expert term in the Standard, thus avoiding any confusion.
Changes are relative to N4835.
Replace all occurrences of
with make_unique_default_initmake_unique_minimal_init
.
Replace all occurrences of
with make_shared_default_initmake_shared_minimal_init
.
Replace all occurrences of
with allocate_shared_default_initallocate_shared_minimal_init
.