Search code examples
c++addressof

Why is std::allocate_shared() allowed to use std::addressof() on an object that is not constructed yet?


According to the cppreference notes for std::to_address(), std::addressof() requires the object to be already constructed:

std::to_address can be used even when p does not reference storage that has an object constructed in it, in which case std::addressof(*p) cannot be used because there is no valid object for the parameter of std::addressof to bind to.

But in this code in the standard library:

// https://github.com/llvm/llvm-project/blob/main/libcxx/include/__memory/shared_ptr.h
template <class _Tp, class _Alloc, class... _Args, __enable_if_t<!is_array<_Tp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&&... __args) {
  using _ControlBlock          = __shared_ptr_emplace<_Tp, _Alloc>;
  using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type;
  __allocation_guard<_ControlBlockAllocator> __guard(__a, 1);
  ::new ((void*)std::addressof(*__guard.__get())) _ControlBlock(__a, std::forward<_Args>(__args)...);
  auto __control_block = __guard.__release_ptr();
  return shared_ptr<_Tp>::__create_with_control_block(
      (*__control_block).__get_elem(), std::addressof(*__control_block));
}

When using placement new, __guard.__get() does not reference storage that has an object constructed in it. Why can std::addressof(*__guard.__get()) be used here? Or is my understanding wrong?


Solution

  • I found the answer in P0653R2.

    Typically the expression addressof(*p) is used but this is not well-defined when p does not reference storage that has an object constructed in it. This means that using this expression to obtain a raw pointer for the purpose of constructing an object (e.g. via a placement new-expression or via an allocator) is incorrect.

    As @n.m.couldbeanAI said, "The standard library doesn't need the call to be legal".