C++中的std::addressof是什么?(如何防止被重载的operator&欺骗)

2次阅读

std::addressof用于获取对象真实内存地址,绕过被重载的operator&;它通过reinterpret_cast等强制取址,仅适用于左值,常见于重载取址符的类型、泛型内存操作及allocator_traits::address等场景。

C++中的std::addressof是什么?(如何防止被重载的operator&欺骗)

std::addressof 用来获取对象真实地址,绕过被重载的 operator&

当你对一个类型调用 &obj,如果它重载了 operator&,编译器就真的会调用那个重载函数——哪怕你只想拿内存地址。这在智能指针、容器内部、或需要做底层指针操作(比如 placement new、std::allocator::address)时很危险。std::addressof 就是专治这个:它用模板和 reinterpret_cast 绕过重载,强制返回对象在内存中的起始地址。

什么时候必须用 std::addressof 而不是 &

常见于以下场景:

  • 自定义类型重载了 operator&(比如某些 RAII 封装类、调试代理类)
  • 写泛型代码(如容器实现、内存分配器),不能假设用户类型是否重载了取址符
  • 调用 std::allocator_traits::address,其默认实现内部就用了 std::addressof
  • 手动调用 placement new 前,确保传入的是原始地址而非重载函数返回值

std::addressof 的行为和限制

它不抛异常,要求参数是左值;对右值(如临时对象)调用是非法的(编译失败)。它的实现本质是:

template<class T> constexpr T* addressof(T& arg) noexcept {     return reinterpret_cast<T*>(         &const_cast<char&>(reinterpret_cast<const volatile char&>(arg))     ); }

关键点:

立即学习C++免费学习笔记(深入)”;

  • 它不依赖 operator&,所以不怕被重载
  • 不支持 const volatile 以外的 cv 限定组合(但通常不影响使用)
  • std::vector<int>::iterator</int> 这类迭代器类型也安全——只要它是可取址的左值
  • 不能用于位域成员(Struct { int x : 4; }; &s.x 本身就不合法,std::addressof 同样不行)

容易踩的坑:别在不该用的地方硬套

最常见的误用是把它当成“更安全的 &”到处用,其实没必要:

  • 普通 POD 类型、标准容器元素、没重载 operator& 的类,直接用 & 更清晰、无额外开销
  • std::unique_ptr<t></t>std::shared_ptr<t></t> 调用 std::addressof(ptr),得到的是智能指针对象本身的地址,不是它指向的 T* —— 别和 ptr.get() 搞混
  • 宏或模板中盲目包裹 std::addressof(x),可能掩盖本该暴露的重载意图(比如某类故意重载 operator& 来禁用取址,这时用 std::addressof 就破坏了设计契约)

真正需要它的地方不多,但一旦需要,漏掉就会导致诡异的地址错乱或未定义行为——尤其是跨库协作或写底层设施时,没人会提醒你那个 & 已经被悄悄劫持了。

text=ZqhQzanResources