[libcxx-commits] [PATCH] D140913: [In Progress] [libc++] make_unique[shared]_for_overwrite
Louis Dionne via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 12 10:24:55 PST 2023
ldionne requested changes to this revision.
ldionne added inline comments.
This revision now requires changes to proceed.
================
Comment at: libcxx/include/__memory/shared_ptr.h:264
+#if _LIBCPP_STD_VER >= 20
+struct __shared_ptr_overwrite_tag{};
+#endif
----------------
Thinking about it some more, I might suggest using something like `__default_initialize_tag` or `__default_construct_tag`? That would be more descriptive when you write e.g.
```
explicit __shared_ptr_emplace(__default_initialize_tag, _Alloc __a) { ... }
```
================
Comment at: libcxx/include/__memory/shared_ptr.h:1020
+ {
+ std::uninitialized_default_construct_n(std::begin(__data_), __count_);
+ }
----------------
================
Comment at: libcxx/include/__memory/shared_ptr.h:1110
+ explicit __bounded_array_control_block(_Alloc const& __alloc, __shared_ptr_overwrite_tag) : __alloc_(__alloc) {
+ std::uninitialized_default_construct_n(std::addressof(__data_[0]), _Count);
+ }
----------------
================
Comment at: libcxx/include/__memory/shared_ptr.h:1156
#if _LIBCPP_STD_VER > 17
template<class _Tp, class _Alloc, class = __enable_if_t<is_bounded_array<_Tp>::value>>
----------------
Maybe you could add a comment like `// bounded array variants` and then `// unbounded array variants` below just to clarify the organization.
================
Comment at: libcxx/include/__memory/shared_ptr.h:1185-1190
+template<class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a)
+{
+ return std::__allocate_shared_bounded_array<_Tp>(__a, __shared_ptr_overwrite_tag{});
+}
----------------
This is a nitpick, but I would move this function below
```
template<class _Tp, class _Alloc, class = __enable_if_t<is_bounded_array<_Tp>::value>>
_LIBCPP_HIDE_FROM_ABI
shared_ptr<_Tp> allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u)
```
I think the way these were initially organized was first the 2 functions for bounded arrays and then the 2 functions for unbounded arrays.
================
Comment at: libcxx/include/__memory/shared_ptr.h:1227-1232
+template<class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI
+shared_ptr<_Tp> make_shared_for_overwrite()
+{
+ return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __shared_ptr_overwrite_tag{});
+}
----------------
Same comment here, let's move this after `make_shared` for bounded arrays.
================
Comment at: libcxx/include/memory:736
+ shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N); // T is U[], C++20
+
template<class T>
----------------
We should also update the release notes.
================
Comment at: libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp:1
+//===----------------------------------------------------------------------===//
+//
----------------
To test these, one thing I might do is use an allocator that reuses an existing buffer that you control. Set up the buffer with some integer pattern in it, then call `foo_for_overwrite()`, and check that the buffer hasn't changed (in particular hasn't been 0'd out, which would happen if we called `new (p) T()` instead of `new (p) T`).
================
Comment at: libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp:105
+
+void testCustomNew() {
+ struct AggregateWithCustomNew {
----------------
================
Comment at: libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp:110-111
+ static void* operator new(size_t n) {
+ auto ptr = ::operator new(n);
+ auto charPtr = reinterpret_cast<char*>(ptr);
+ *charPtr = 'x';
----------------
I don't feel we gain much from `auto` here.
I think this is testing two things at once, and we should have two tests instead. One for checking that the in-class `operator new` is called, and then another test to check that we don't value-initialize the underlying memory when we call `make_unique_for_overwrite`. WDYT?
================
Comment at: libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.pass.cpp:124
+ };
+
+ // single with custom operator new
----------------
To test that we're not value initializing, I would suggest overriding the global `operator new` with one that always returns `0xDEADBEEF`'d memory (or whatever pattern you fancy). Then you can check that the memory after calling `xxx_for_overwrite` is still `0xDEADBEEF`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D140913/new/
https://reviews.llvm.org/D140913
More information about the libcxx-commits
mailing list