Document number: | P2042r0 | |
---|---|---|
Date: | 2020-01-11 | |
Audience: | LEWG | |
Reply-to: | Andrzej Krzemieński <akrzemi1 at gmail dot com> |
make_shared_default_init
This document is a response to National body comment [DE002],
which requests to rename functions make_shared_default_init
, make_unique_default_init
and
allocate_shared_default_init
, as there exist users that incorrectly infer these functions' semantics from
their names. In this paper we list the suggested alternate names for these functions, which have been collected from
the reflector discussions.
The following (potentially contradictory) criteria have been expressed for the desired name of these functions:
make_shared_noinit
).
make_shared_default_init
.)
std::uninitialized_default_construct
.)
make_shared_default_init
This name is consistent with core language and more-less (make_shared_default_init
vs make_shared_default_construct
) with the Standard Library.
The only problem is the issue inidcated in [DE002], that for
people not familiar with core terms word "init" is misleading as it implies a state that can be read.
make_shared_default_construct
Almost same as above, but we get a 100% compatibility with the Standard Library.
make_shared_uninitialized
(+ a constraint) This is what [P1973r0] proposes.
This avoids using the name "initialized" and does not mislead people who infer semantics from function name. To some extent the name reflects what
the function does, because for the types that the function is constrained to, there is little difference between being initialized an uninitialized.
But this solution has its own issues. First, in addition to name, it changes the design,
so that the usage of the function is impeded in generic contexts. The name no longer reflects the core terms or the Standard Library names.
It is also misleading, this time to another group of people, who follow the core terms. "Uninitialized", as in
std::uninitialized_default_construct
, implies that we are left with raw memory and some initialization — even if vacuous initialization —
still needs to be performed by the caller.
make_shared_minimal_init
This is what [P1978r0] proposes. Arguably, its name reflects the intention somewhat better, as the purpose of invoking this function is to perform as fast initialization as possible for the subsequent value assignment. But it departs from core terms, and does not actually address [DE002], because the misleading term "init" is still present.
make_shared_noinit
This is the name used in the original implementation in Boost. It addresses [DE002] as "noinit" implies that no "initialization" is performed. Drawbacks: it doesn't use core terms, and is somewhat misleading as some it might indicate that not even vacuous initialization has been performed.
make_shared_unsafe_init
, make_shared_weak_init
These names have prefixes that alert about something fishy, but they still have "init", which is potentially misleading. They do not reflect core terms. They also don't really reflect what the function does. Unless we introduce a new core term "weak initialization".
make_shared_trivial_init
Same as above, except a bit more misleading, as it implies that it only works for trivial types, or that it skips the constructor for types that have one.
make_shared_nonvalue_init
"Nonvalue" hints that the produced value may be fishy, but it is not clear if it hints enough that it cannot be read. Still, not following core terms, and has "init".
make_shared_partially_formed_value
, make_shared_with_partially_formed_value
"Partially formed value" sounds dangerous enough to discourage people form reading the value. It doesn't contain "init". It reflects the intent a bit. But it is not actually true because for types with default constructor the value is actually fully formed.
make_shared_for_overwrite
, make_shared_with_no_guaranteed_value
Clearly reflect the intent. Do not have "init". Do not invent terms. Maybe too descriptive.
make_shared_unspecified_value
Uses familiar core terms, maybe somewhat libelarly. Still, the uninitiated may think that unspecified value can be read.
make_shared_valueless
, make_shared_with_valueless
"Valueless" is used in std::variant
and is perhaps sufficiently scarry.
The two contexts are similar in the sense that in either case you do not want to read the value, but to overwrite it.
make_shared_with_discarded_value
, make_shared_discarded_value
You do not want to read a discarded value, don't you?
make_shared_indeterminate_value
, make_shared_with_indeterminate_value
, make_shared_indeterminate This uses the core term "indeterminate value" which is the right term at least for trivial types. It is not the right term
for types with default constructor, but the meaning should be sufficiently clear from the context. This makes it incompatible with
std::uninitialized_default_construct
.
The reflector discussions also suggested that the core terms themselves could be changed to be easier to consume by the uninitiated. However, this would require the coordination between the working groups that may not be feasible for C++20. So, either this idea needs to be abandoned, or LEWG can preemptively invent intuitive terms in hopes that CWG will adapt in the future.
It should be noted that std::make_shared_default_init
is acompanied by the
corresponding feature test macro __cpp_lib_smart_ptr_default_init
. Should LEWG decide to change the name of the
function, does the name of the macro also require a change?
make_shared_default_init
functions and do nothing more",
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1978r0.html).