news 2026/3/19 17:53:16

跟我学C++中级篇——取地址操作

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
跟我学C++中级篇——取地址操作

一、取地址

在C/C++开发中,指针操作既是一个难点,同时也是一个无法绕开的知识点。一个对象的指针,可以说就是一个对象的地址。那么如何取得这个对象指针呢?或者说如何取得对象地址呢?在传统的开发中,开发者可以通过“&”运算符来获取对象的指针即地址。而在C++11中,开发者又发现了一个std::addressof也可以达到同样的功能。下面将对它们之间的区别和联系进行分析。

二、std::addressof

在C++11中提供了一个接口std::addressof,它的作用与“&”运算符的功能一样也是获取一个对象的实际的地址。看一下其定义:

//定义template<class T>T*addressof(T&arg);//实现template<typename _Tp>_GLIBCXX_NODISCARDinline_GLIBCXX17_CONSTEXPR _Tp*addressof(_Tp&__r)noexcept{returnstd::__addressof(__r);}template<typename _Tp>inline_GLIBCXX_CONSTEXPR _Tp*__addressof(_Tp&__r)_GLIBCXX_NOEXCEPT{return__builtin_addressof(__r);}

__builtin_addressof函数是gcc内置的取地址的函数,它不管&运算符是否被重载都会获取对象的地址。

三、源码

其源实现基于两种场景:

  1. 基于编译器内置函数
    这是非常广泛的一种方法,代码如下:
template<typename _Tp>_GLIBCXX_NODISCARDinline_GLIBCXX17_CONSTEXPR _Tp*addressof(_Tp&__r)noexcept{returnstd::__addressof(__r);}template<typename _Tp>inline_GLIBCXX_CONSTEXPR _Tp*__addressof(_Tp&__r)_GLIBCXX_NOEXCEPT{return__builtin_addressof(__r);}

__builtin_addressof函数是gcc内置的取地址的函数,它不管&运算符是否被重载都会获取对象的地址。
2. 基于非编译器内置函数
简易实现如下:

template<class T>T*addressof(T&arg){return(T*)&(char&)arg;}

正规的实现如下:

template<typename _Tp>inline_Tp*__addressof(_Tp&__r)_GLIBCXX_NOEXCEPT{returnreinterpret_cast<_Tp*>(&const_cast<char&>(reinterpret_cast<constvolatilechar&>(__r)));}template<typename _Tp>inline_Tp*addressof(_Tp&__r)noexcept{returnstd::addressof(__r);}

从简单实现其实可以更好的理解其实现的过程,先是强制转成字符类型的引用(char&),这样做的目的一是防止导致对&运算符的重载操作(char类型作为基础类型没有重载&);二是可以防止出现转换为其它类型(大于1字节)可能导致的内存对齐动作(地址就有可能变化)。然后取地址获取真实的地址即&(char&)中的外面的&(char没有重载&),再强制转成指定类型的指针。
后面的实现,则是为了安全和效率起见,所作的安全控制和内联(inline),说一下const volatile,一个变量既可以是常量又可以可变。这要从两个角度来理解,比如一个寄存器,对程序而言它是常量,不应该尝试去改变它。但对硬件而言,它可能被改变。它的目的是为了防止编译器优化,确保获取准确的地址。而上面的const_cast则去除刚刚增加的const volatile。其它就非常好理解了。

四、应用场景和限制

既然有&可以获取地址,为什么又要造出一个std::addressof。大家都知道,除了一些特定的运算符不可以重载的话,大多数的运算符是可以被重载的,其中就包含&运算符。那么问题来了,在被重载了&运算符的对象中如果还是用&来取地址的话,会是什么情况呢?看下面的例程:

#include<iostream>#include<memory>structDemo{int*operator&(){return&b_;}int*getaddr(){return&a_;}inta_;intb_;};intmain(){Demo d;std::cout<<"d address:"<<&d<<",d.a_ address:"<<d.getaddr()<<std::endl;std::cout<<" addressof get addr:"<<std::addressof(d)<<std::endl;}

即使不运行代码也可以看出来,直接使用&获取的地址一定是有问题的。所以通过上面的代码可以总结出来,&和std::addressof的不同主要在于对重载&的应用的不同。后者可以始终正确的获取对象的地址。或者可以这样理解,在没有重载&运算符的情况下,二者的功能是一致的,编译器会将其优化化相同的代码。不过,std::addressof不能用于不完整类型,且在C++17前不允许用于右值。
std::addressof理论是在可以排除前面的限制情况下都可以使用。但有几个典型的应用场景:

  1. 在模板编程中必须使用
  2. &重载的情况下
  3. 确保获取准确的地址需求中
  4. 在处理无法主动控制的库或类型时

&的优势就在于代码简洁,清晰明了。所以如何选择二者,就看开发者对实际代码的了解程度了。在非上面几个典型的应用场景下,可以大胆的使用。能省一点是一点嘛。

五、例程

看一个cppreference上的例子:

#include<iostream>#include<memory>template<class T>structPtr{T*data;Ptr(T*arg):data(arg){}~Ptr(){delete data;}T**operator&(){return&data;}};template<class T>voidf(Ptr<T>*p){std::cout<<"Ptr overload called with p = "<<p<<'\n';}voidf(int**p){std::cout<<"int** overload called with p = "<<p<<'\n';}intmain(){Ptr<int>p(newint(42));f(&p);// calls int** overloadf(std::addressof(p));// calls Ptr<int>* overload}

上面的代表显示的结果应该是一致的才对。很好理解,第一个打印虽然重载的&运算符返回二级指针,但实际调用也是一个二级指针的对象转换,再加上&本身的取地址,恰恰是一级指针。

六、总结

任何技术不可能都是面面俱到的,新技术的出现,有的是颠覆性的修改而有的则是完善性的修改。std::addressof其实可以理解为对&的一种完善,它把一些可能出现的漏洞以及在发现这些漏洞后可能导致的代码复杂性做了统一的处理。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/16 2:02:48

基于LSTM模型的订单流数据量化交易策略构建

1. 金融市场微观结构与订单流数据特性 1.1 市场微观结构核心要素解析 金融市场微观结构理论关注交易机制如何影响价格形成过程&#xff0c;其核心要素包含订单簿动态、交易发起方特征、流动性供给模式及信息传递效率。在高频交易环境下&#xff0c;每笔交易都携带买卖双方的行…

作者头像 李华
网站建设 2026/3/16 5:36:03

ToB获客破局:精准数据+AI外呼,重构效率新模式

在ToB赛道&#xff0c;获客始终是企业增长的核心命题。传统模式下&#xff0c;展会地推成本高企、人工外呼效率低下、客户线索良莠不齐等痛点&#xff0c;让多数企业陷入“投入大、转化低”的困境。如今&#xff0c;精准获客数据与AI机器人外呼的深度融合&#xff0c;正打破这一…

作者头像 李华
网站建设 2026/3/15 5:49:06

vivo技术开放日议题提交:探讨手机端轻量模型应用

vivo技术开放日议题&#xff1a;轻量模型如何重塑手机端AI体验 在智能手机日益成为个人计算中枢的今天&#xff0c;用户对“智能”的期待早已超越语音唤醒和拍照优化。他们希望手机能真正理解问题、辅助决策&#xff0c;甚至像一位随身导师那样&#xff0c;帮自己解一道数学题、…

作者头像 李华
网站建设 2026/3/16 5:36:05

Debian/RedHat仓库构建:为企业用户提供APT/YUM源

Debian/RedHat仓库构建&#xff1a;为企业用户提供APT/YUM源 在企业级AI系统部署中&#xff0c;一个常见的困境是&#xff1a;明明模型已经在测试环境跑通&#xff0c;却因为“少装了一个依赖”或“版本不一致”&#xff0c;导致在生产集群上反复踩坑。尤其是当团队需要在数百…

作者头像 李华
网站建设 2026/3/16 6:20:15

OPPO开发者大会合作洽谈:终端侧部署可能性探讨

OPPO开发者大会合作洽谈&#xff1a;终端侧部署可能性探讨 在智能手机竞争日趋白热化的今天&#xff0c;硬件配置的军备竞赛已接近瓶颈&#xff0c;系统体验与AI能力正成为厂商突围的关键。OPPO作为国内领先的智能终端品牌&#xff0c;近年来持续加码AI原生体验布局。而当前一个…

作者头像 李华