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 casestd::addressof(*p)
cannot be used because there is no valid object for the parameter ofstd::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?
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".