@@ -557,6 +557,8 @@ auto Typeid() -> decltype(auto) {
557
557
struct {
558
558
template <typename T>
559
559
[[nodiscard]] auto cpp2_new (auto && ...args) const -> std::unique_ptr<T> {
560
+ // Prefer { } to ( ) so that initializing a vector<int> with
561
+ // (10), (10, 20), and (10, 20, 30) is consistent
560
562
if constexpr (requires { T{CPP2_FORWARD (args)...}; }) {
561
563
// This is because apparently make_unique can't deal with list
562
564
// initialization of aggregates, even after P0960
@@ -571,7 +573,23 @@ struct {
571
573
[[maybe_unused]] struct {
572
574
template <typename T>
573
575
[[nodiscard]] auto cpp2_new (auto && ...args) const -> std::shared_ptr<T> {
576
+ // Prefer { } to ( ) as noted for unique.new
577
+ //
578
+ // Note this does mean we don't get the make_shared optimization a lot
579
+ // of the time -- we can restore that as soon as make_shared improves to
580
+ // allow list initialization. But the make_shared optimization isn't a
581
+ // huge deal anyway: it saves one allocation, but most of the cost of
582
+ // shared_ptrs is copying them and the allocation cost saving is probably
583
+ // outweighed by just a couple of shared_ptr copies; also, the make_shared
584
+ // optimization has the potential downside of keeping the raw storage
585
+ // alive longer when there are weak_ptrs. So, yes, we can and should
586
+ // restore the make_shared optimization as soon as make_shared supports
587
+ // list init, but I don't think it's all that important AFAIK
574
588
if constexpr (requires { T{CPP2_FORWARD (args)...}; }) {
589
+ // Why this calls 'unique.new': The workaround to use { } initialization
590
+ // requires calling naked 'new' to allocate the object separately anyway,
591
+ // so reuse the unique.new path that already does that (less code
592
+ // duplication, plus encapsulate the naked 'new' in one place)
575
593
return unique.cpp2_new <T>(CPP2_FORWARD (args)...);
576
594
}
577
595
else {
0 commit comments