You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何std::allocate_shared()可对未构造对象使用std::addressof()?

关于std::addressof()在未构造对象存储空间上的使用疑问

根据cppreference中std::to_address()的注释:

即使p指向的存储空间中尚未构造对象,仍可使用std::to_address();这种情况下无法使用std::addressof(*p),因为std::addressof()的参数没有可绑定的有效对象。

但在LLVM libcxx的allocate_shared实现代码中:

// 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));
}

在placement new调用时,__guard.__get()指向的存储空间中还未构造_ControlBlock对象,却使用了std::addressof(*__guard.__get()),这看起来和cppreference的注释矛盾,这是为什么?是我的理解有误吗?


问题解答

这里的核心是对C++标准中指针解引用与对象生命周期边界的细节理解,以及std::addressof的实现特性:

  • 解引用未构造对象的特殊允许场景:C++标准并非完全禁止解引用指向未构造对象的指针。只要不对解引用得到的“伪对象”执行任何依赖对象生命周期的操作(比如调用成员函数、访问非静态成员、触发虚函数机制等),仅做取地址这类无副作用的操作是被允许的。

  • std::addressof的本质:std::addressof的设计目的是绕过对象重载的operator&,直接获取对象的真实内存地址。它的实现不依赖对象的构造状态——既不会访问对象的成员,也不会触发任何对象生命周期相关的行为。std::addressof(*p)本质上就是在获取指针p指向的内存起始地址,和直接使用static_cast<void*>(p)的效果一致,只是语法上通过解引用再取地址的方式实现。

  • cppreference注释的语境:cppreference的注释是在强调,不能将*p绑定到需要有效对象的引用场景(比如传入一个要求T&参数的函数),或者对*p执行任何需要对象已构造的操作。但std::addressof的参数是模板化的引用,它对这个“伪对象”的处理仅停留在取地址层面,完全符合标准允许的操作范围。

  • libcxx实现的合规性:这段代码是符合C++标准的。__guard.__get()返回的指针指向的是已经分配好、且对齐正确的内存区域,解引用后仅用于取地址,没有触发任何对象生命周期的操作,因此是安全合法的。

内容的提问来源于stack exchange,提问作者ValueError

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 02:43:10