Add absl::make_unique_for_overwrite This is a polyfill for C++20's `std::make_unique_for_overwrite`. https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique PiperOrigin-RevId: 875171828 Change-Id: I270264c258ba6629ccb7b93030ae3b298b2a8b23
diff --git a/absl/memory/memory.h b/absl/memory/memory.h index 3508135..f0f7aea 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h
@@ -96,6 +96,53 @@ // should use `std::make_unique`. using std::make_unique; +namespace memory_internal { + +// Traits to select proper overload and return type for +// `absl::make_unique_for_overwrite<>`. +template <typename T> +struct MakeUniqueResult { + using scalar = std::unique_ptr<T>; +}; +template <typename T> +struct MakeUniqueResult<T[]> { + using array = std::unique_ptr<T[]>; +}; +template <typename T, size_t N> +struct MakeUniqueResult<T[N]> { + using invalid = void; +}; + +} // namespace memory_internal + +// These are make_unique_for_overwrite variants modeled after +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1973r1.pdf +// Unlike absl::make_unique, values are default initialized rather than value +// initialized. +// +// `absl::make_unique_for_overwrite` overload for non-array types. +template <typename T> +typename memory_internal::MakeUniqueResult<T>::scalar + make_unique_for_overwrite() { + return std::unique_ptr<T>(new T); +} + +// `absl::make_unique_for_overwrite` overload for an array T[] of unknown +// bounds. The array allocation needs to use the `new T[size]` form and cannot +// take element constructor arguments. The `std::unique_ptr` will manage +// destructing these array elements. +template <typename T> +typename memory_internal::MakeUniqueResult<T>::array + make_unique_for_overwrite(size_t n) { + return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]); +} + +// `absl::make_unique_for_overwrite` overload for an array T[N] of known bounds. +// This construction will be rejected. +template <typename T, typename... Args> +typename memory_internal::MakeUniqueResult<T>::invalid + make_unique_for_overwrite(Args&&... /* args */) = delete; + // ----------------------------------------------------------------------------- // Function Template: RawPtr() // -----------------------------------------------------------------------------
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index fafd3a4..aeb6001 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc
@@ -64,6 +64,11 @@ EXPECT_EQ(0, DestructorVerifier::instance_count()); } +TEST(MakeUniqueForOverwriteTest, Basic) { + std::unique_ptr<int> p = absl::make_unique_for_overwrite<int>(); + p = absl::make_unique_for_overwrite<int>(); +} + // InitializationVerifier fills in a pattern when allocated so we can // distinguish between its default and value initialized states (without // accessing truly uninitialized memory). @@ -87,6 +92,28 @@ int b; }; +TEST(Initialization, MakeUniqueForOverwrite) { + auto p = absl::make_unique_for_overwrite<InitializationVerifier>(); + + int pattern; + memset(&pattern, InitializationVerifier::kDefaultScalar, sizeof(pattern)); + + EXPECT_EQ(pattern, p->a); + EXPECT_EQ(pattern, p->b); +} + +TEST(Initialization, MakeUniqueForOverwriteArray) { + auto p = absl::make_unique_for_overwrite<InitializationVerifier[]>(2); + + int pattern; + memset(&pattern, InitializationVerifier::kDefaultArray, sizeof(pattern)); + + EXPECT_EQ(pattern, p[0].a); + EXPECT_EQ(pattern, p[0].b); + EXPECT_EQ(pattern, p[1].a); + EXPECT_EQ(pattern, p[1].b); +} + struct ArrayWatch { void* operator new[](size_t n) { allocs().push_back(n); @@ -99,6 +126,17 @@ } }; +TEST(MakeUniqueForOverwriteTest, Array) { + // Ensure state is clean before we start so that these tests + // are order-agnostic. + ArrayWatch::allocs().clear(); + + auto p = absl::make_unique_for_overwrite<ArrayWatch[]>(5); + static_assert(std::is_same<decltype(p), std::unique_ptr<ArrayWatch[]>>::value, + "unexpected return type"); + EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch))); +} + TEST(RawPtrTest, RawPointer) { int i = 5; EXPECT_EQ(&i, absl::RawPtr(&i));