当前位置: 首页 > news >正文

跟我学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其实可以理解为对&的一种完善,它把一些可能出现的漏洞以及在发现这些漏洞后可能导致的代码复杂性做了统一的处理。

http://www.jsqmd.com/news/204748/

相关文章:

  • 计算机毕业设计springboot城市交通管理系统 基于SpringBoot的智慧城市道路交通调度平台 SpringBoot+MySQL构建的城区交通流在线管控系统
  • 2026年上海全屋定制品牌推荐:5大实力品牌深度解析与横向对比评测。 - 品牌推荐
  • 基于LSTM模型的订单流数据量化交易策略构建
  • 2026年广州全屋定制品牌推荐:设计落地能力与服务体系双维度实测榜单。 - 品牌推荐
  • 计算机毕业设计springboot北京市民宿推荐系统 基于 SpringBoot 的首都民宿智能推荐平台 融合协同过滤的京城民宿优选系统
  • 百度飞桨PaddleHub兼容性测试进展:多框架生态融合
  • LeetCode 137「Single Number II」详解:位计数 + 模3运算 + 状态机
  • QCon主题分享征集:吸引一线工程师参与实践
  • 2026上海雅思培训机构哪家好?真实口碑机构推荐 - 品牌排行榜
  • 大模型开发平台:高校大模型教学与开发一体化平台
  • 2026年靠谱的柚木定制柜,柚木柜体,缅甸柚木柜厂家采购优选指南 - 品牌鉴赏师
  • 新定义(24年台州一中自主招生第25题)
  • 报表自动化进阶:Java精确操控Excel打印页边距的实战方法
  • GitLab CI共享Runner配置:开源项目自动测试VibeThinker
  • 2026上海雅思培训机构测评:师资与口碑综合分析 - 品牌排行榜
  • 百度世界大会合作伙伴招募:联合发布行业解决方案
  • 管理信息系统在线作业如何告别纸上谈兵?
  • 2026上海托福培训机构推荐:口碑机构实力盘点 - 品牌排行榜
  • 义乌汽车租赁公司亲测调研报告 - 呼呼拉呼
  • PowerShell脚本自动化:定时执行VibeThinker批处理任务
  • C语言fscanf读取文件时,文件指针怎么移动的?
  • 协同共赢 数智冷链如何构建餐饮连锁高质量发展新生态 - 博客万
  • 2026年市面上靠谱的磁力泵公司电话,防腐离心泵/耐酸离心泵/耐腐蚀氟塑料泵/不锈钢磁力泵,磁力泵生产厂家电话 - 品牌推荐师
  • 2025-2031年全球与中国高低温试验箱市场竞争格局及重点企业竞争力深度分析 - 品牌推荐大师1
  • 2025高定服装加盟优选,助力创业者抢占市场!,高定服装加盟采购色麦新中式市场认可度高 - 品牌推荐师
  • 2025年阁楼货架品牌盘点:口碑与品质的双重保障,模具仓库货架厂家批发/重型仓库货架生产厂商/仓储货架安装厂家阁楼货架厂商哪个好 - 品牌推荐师
  • 上海全屋定制哪家更专业?2026年5强品牌权威测评与最终推荐! - 品牌推荐
  • 用户行为分析看板:了解VibeThinker实际使用模式
  • FP16量化尝试:进一步压缩VibeThinker模型体积的可能性
  • 2026年广州全屋定制品牌推荐:聚焦顶奢楼盘项目的5家服务商实力盘点。 - 品牌推荐