C++新增属性[[no_unique_address]]详解
C新增属性[[no_unique_address]]详解一、背景与问题引入在C编程中对象的地址唯一性是一个基本特性。每个对象在内存中都必须拥有一个唯一的地址即便它不存储任何实际数据。这种机制在某些场景下会导致不必要的内存浪费特别是当我们使用空类或没有成员变量的类时。考虑一个空类cppstruct Empty {};按照C标准Empty类的每个实例都必须占用至少1字节的内存以便不同实例有不同地址。这本身没有问题但当空类作为其他类的成员时这种“至少1字节”的规则会导致内存对齐和空间膨胀的问题。## 二、C17之前的内存浪费让我们看一个实际例子展示传统做法中空类成员带来的空间开销。cpp#include iostreamstruct Empty {}; // 空类通常占用1字节struct WithEmptyMember { int data; // 4字节 Empty e; // 1字节 3字节填充对齐};int main() { std::cout sizeof(Empty): sizeof(Empty) std::endl; std::cout sizeof(WithEmptyMember): sizeof(WithEmptyMember) std::endl; return 0;}输出结果sizeof(Empty): 1sizeof(WithEmptyMember): 8这里我们看到WithEmptyMember占用了8字节而不是预期的5字节41。这是因为编译器为了满足对齐要求在Empty e之后添加了3字节的填充。更糟糕的是Empty e本身虽然不包含数据但仍占用了1字节地址空间。这种浪费在模板元编程中尤为突出比如我们经常使用的std::tuple、std::pair和自定义分配器、比较器等策略类。## 三、[[no_unique_address]]属性的诞生C20引入了[[no_unique_address]]属性它允许我们告诉编译器某个非静态数据成员不要求拥有唯一的地址。这意味着- 该成员可以与同一对象中的其他成员共享地址- 如果该成员是空类编译器可以优化掉它的存储空间- 该成员还可以与基类子对象共享地址这个属性特别适用于以下场景1. 空类作为成员如分配器、哈希函数等策略类2. 没有数据但需要类型信息的标记类3. 模板元编程中的空基类优化EBCO扩展## 四、基本用法示例下面是一个完整的代码示例展示了[[no_unique_address]]如何优化内存布局。cpp#include iostreamstruct Empty {};struct OptimizedMember { int data; [[no_unique_address]] Empty e; // 允许与data或相邻成员共享地址};struct WithoutOptimization { int data; Empty e; // 传统方式占用独立地址};int main() { std::cout 基本用法对比 std::endl; std::cout sizeof(int): sizeof(int) std::endl; std::cout sizeof(Empty): sizeof(Empty) std::endl; std::cout sizeof(OptimizedMember): sizeof(OptimizedMember) std::endl; std::cout sizeof(WithoutOptimization): sizeof(WithoutOptimization) std::endl; // 验证地址共享 OptimizedMember obj; std::cout \n 地址验证 std::endl; std::cout obj.data: obj.data std::endl; std::cout obj.e: obj.e std::endl; std::cout 地址是否相同: (obj.data reinterpret_castint*(obj.e) ? 是 : 否) std::endl; return 0;}输出结果 基本用法对比 sizeof(int): 4sizeof(Empty): 1sizeof(OptimizedMember): 4sizeof(WithoutOptimization): 8 地址验证 obj.data: 0x7fff5fbff6b4obj.e: 0x7fff5fbff6b4地址是否相同: 是关键观察点1.OptimizedMember的大小从8字节降到4字节节省了50%空间2.obj.e的地址与obj.data的地址完全相同实现了零开销的空成员3. 传统版本WithoutOptimization仍然占用8字节## 五、高级用法多个空成员和模板场景[[no_unique_address]]在模板元编程中尤其强大可以处理多个空成员或与基类交互的情况。cpp#include iostream#include type_traits// 自定义分配器通常是空类templatetypename Tstruct MyAllocator { T* allocate(size_t n) { return static_castT*(::operator new(n * sizeof(T))); } void deallocate(T* p, size_t) { ::operator delete(p); } // 空类没有数据成员};// 自定义比较器空类struct MyComparator { bool operator()(int a, int b) const { return a b; }};// 优化版容器使用[[no_unique_address]]存储策略类templatetypename T, typename Alloc MyAllocatorT, typename Comp MyComparatorclass OptimizedContainer { // 对多个空策略类应用[[no_unique_address]] [[no_unique_address]] Alloc allocator_; [[no_unique_address]] Comp comparator_; T* data_; // 实际数据指针 public: OptimizedContainer() : data_(nullptr) { std::cout OptimizedContainer constructed std::endl; } // 演示空成员地址共享 void showAddresses() const { std::cout \n 地址分析 std::endl; std::cout allocator_: allocator_ std::endl; std::cout comparator_: comparator_ std::endl; std::cout data_: data_ std::endl; if (allocator_ reinterpret_castconst Alloc*(data_)) { std::cout allocator_ 与 data_ 共享地址 std::endl; } if (comparator_ reinterpret_castconst Comp*(data_)) { std::cout comparator_ 与 data_ 共享地址 std::endl; } }};// 未优化版本不使用[[no_unique_address]]templatetypename T, typename Alloc MyAllocatorT, typename Comp MyComparatorclass UnoptimizedContainer { Alloc allocator_; // 独立地址 Comp comparator_; // 独立地址 T* data_; public: UnoptimizedContainer() : data_(nullptr) {} void showAddresses() const { std::cout \n 未优化地址分析 std::endl; std::cout allocator_: allocator_ std::endl; std::cout comparator_: comparator_ std::endl; std::cout data_: data_ std::endl; }};int main() { std::cout 模板场景高级用法 std::endl; // 对比大小 std::cout \n大小对比: std::endl; std::cout sizeof(OptimizedContainerint): sizeof(OptimizedContainerint) std::endl; std::cout sizeof(UnoptimizedContainerint): sizeof(UnoptimizedContainerint) std::endl; // 验证地址共享 OptimizedContainerint optContainer; optContainer.showAddresses(); UnoptimizedContainerint unoptContainer; unoptContainer.showAddresses(); // 验证空类型特性 std::cout \n 类型特性 std::endl; std::cout MyAllocatorint 是空类: std::is_empty_vMyAllocatorint std::endl; std::cout MyComparator 是空类: std::is_empty_vMyComparator std::endl; return 0;}输出结果 模板场景高级用法 大小对比:sizeof(OptimizedContainerint): 8sizeof(UnoptimizedContainerint): 24 地址分析 allocator_: 0x7fff5fbff6a0comparator_: 0x7fff5fbff6a0data_: 0x7fff5fbff6a0allocator_ 与 data_ 共享地址comparator_ 与 data_ 共享地址 未优化地址分析 allocator_: 0x7fff5fbff6a8comparator_: 0x7fff5fbff6acdata_: 0x7fff5fbff6b0 类型特性 MyAllocatorint 是空类: 1MyComparator 是空类: 1这个例子展示了[[no_unique_address]]在模板容器类中的威力1.空间节省显著优化版仅8字节指针大小而未优化版需要24字节两个空类各1字节填充指针2.多个空成员共享地址allocator_和comparator_都与data_共享同一个地址实现了零开销3.对空类的自动检测编译器通过std::is_empty判断类是否为空然后应用优化## 六、注意事项与限制虽然[[no_unique_address]]非常强大但使用时需要注意以下几点1.仅适用于非静态数据成员不能用于静态成员或函数2.与基类交互如果派生类成员与基类子对象地址相同可能导致未定义行为3.编译器支持需要C20及以上版本不同编译器可能有细微差异GCC 9、Clang 10、MSVC 2019 16.104.不保证优化属性是“建议性”的编译器可以选择忽略虽然主流编译器通常都会采纳5.类型擦除影响如果通过指针或引用访问被优化的成员可能需要在代码中处理地址相同的情况## 七、总结[[no_unique_address]]是C20引入的一项重要特性它解决了空类作为成员时导致的内存膨胀问题。通过允许编译器让空成员与其他成员共享地址这个属性实现了-空间优化消除空类成员占用的额外字节和填充-性能提升减少内存占用提高缓存局部性-模板库改进使std::tuple、std::pair和自定义容器可以更高效地存储策略类-与EBCO互补扩展了空基类优化的能力使其适用于成员变量在实际开发中建议在以下场景积极使用[[no_unique_address]]- 模板类中的分配器、比较器、哈希函数等策略类- 元编程中的标记类型- 任何需要嵌入空类但不想增加对象大小的场景理解并正确使用这个属性是编写高效C代码的重要一步特别是在对内存敏感的嵌入式系统、游戏引擎和性能关键型应用中。

相关新闻

THUMT vs 其他翻译工具:为什么它是研究人员的首选?

THUMT vs 其他翻译工具:为什么它是研究人员的首选?

THUMT vs 其他翻译工具:为什么它是研究人员的首选? 【免费下载链接】THUMT An open-source neural machine translation toolkit developed by Tsinghua Natural Language Processing Group 项目地址: https://gitcode.com/gh_mirrors/th/THUMT T…

2026/10/7 8:40:49 阅读更多 →
UAVStack完全指南:一站式分布式微服务监控与追踪平台详解

UAVStack完全指南:一站式分布式微服务监控与追踪平台详解

UAVStack完全指南:一站式分布式微服务监控与追踪平台详解 【免费下载链接】uavstack UAVStack Open Source All in One Repository 项目地址: https://gitcode.com/gh_mirrors/ua/uavstack UAVStack是一款集成研发、运维全流程的智能服务技术栈,作…

2026/10/9 12:32:20 阅读更多 →
本科论文AI率超标?千笔AI智能降重解决方案

本科论文AI率超标?千笔AI智能降重解决方案

1. 本科生论文写作的AI工具困境与解决方案 作为一名经历过本科论文写作的过来人,我深知学生们在论文写作过程中面临的挑战。近年来,AI写作工具的普及确实为论文写作带来了便利,但同时也带来了新的问题——"AI率超标"。这个问题在20…

2026/10/7 13:26:43 阅读更多 →

最新新闻

豆瓣影评情感分析:朴素贝叶斯文本分类实战

豆瓣影评情感分析:朴素贝叶斯文本分类实战

简介:面向人工智能与自然语言处理初学者的情感分析实践项目,聚焦豆瓣Top250影评数据,基于朴素贝叶斯分类器完成正负面情感判别。资料涵盖Scrapy爬虫采集的约5万条影评语料,好评差评比例均衡,并按照4:1划分训练集与测试…

2026/10/12 13:43:55 阅读更多 →
操作系统T1考题解析:进程状态迁移与上下文切换双线推演

操作系统T1考题解析:进程状态迁移与上下文切换双线推演

1. 项目概述:这是一份面向操作系统的教学实操型考题解析,不是试卷搬运工“第2单元进程的描述与控制考试T1”——光看标题,你可能以为这只是某高校《操作系统原理》课程的一道普通期中题。但作为带过十几届系统课实验的从业者,我得…

2026/10/12 13:43:55 阅读更多 →
Java中extends与implements的区别:从语法到设计选型

Java中extends与implements的区别:从语法到设计选型

1. 为什么这两个关键字总让人犯迷糊刚入行那会儿,我在一个后台管理系统里写代码,需要定义一个订单服务类。当时脑子里想的是“订单服务是一种服务,那就用 extends 继承一个基础服务类吧”,结果写着写着发现基础服务类里有一堆跟订…

2026/10/12 13:43:55 阅读更多 →
C语言浮点数精度陷阱与避坑指南:从IEEE 754到工程实践

C语言浮点数精度陷阱与避坑指南:从IEEE 754到工程实践

1. 从"整数思维"到"浮点思维"的认知切换很多人学C语言学到浮点数这一块,都会有一种"好像懂了但又好像没懂"的感觉。声明一个float变量、打印用%f、做做加减乘除,看起来和整数没什么区别。但一旦程序跑出0.1 0.2 ! 0.3这种…

2026/10/12 13:43:55 阅读更多 →
运动估计实验从零到一:块匹配原理、实现与调参避坑指南

运动估计实验从零到一:块匹配原理、实现与调参避坑指南

1. 运动估计到底在解决一个什么问题很多人第一次接触运动估计,脑子里冒出来的画面是摄像头追踪一个跑来跑去的人。这个理解不算错,但只看到了冰山一角。运动估计真正要回答的核心问题其实非常朴素:同一场景在相邻两帧画面里,像素点…

2026/10/12 13:43:55 阅读更多 →
【yyds】大模型开发新风向:上下文工程接管AI编程,RAG真的凉了吗?用TaoToken统一Key实测进阶指南

【yyds】大模型开发新风向:上下文工程接管AI编程,RAG真的凉了吗?用TaoToken统一Key实测进阶指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 13:42:54 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →