0

0

C++联合体怎么用 C++ union节省内存的使用技巧【底层】

尼克

尼克

发布时间:2026-02-02 16:07:02

|

681人浏览过

|

来源于php中文网

原创

union本质是内存重叠,所有成员共享同一地址且不自动记录活跃类型,需手动管理生命周期与类型标识,否则引发未定义行为;推荐用std::variant替代以获类型安全。

c++联合体怎么用 c++ union节省内存的使用技巧【底层】

union 在 C++ 中本质是内存重叠,不是类型安全的“多选一”

union 的所有成员共享同一块内存地址,sizeof 取的是最大成员的大小,但**不会自动记录当前实际存的是哪个类型**。这意味着你必须自己维护“活跃成员”的状态,否则读错类型就是未定义行为(UB)。比如写入 int 后读成 float,结果完全不可预测——这不是 bug,是设计如此。

常见错误现象:union 成员初始化后值异常、调试时看到“幻数”、跨平台行为不一致(尤其涉及浮点/整数位模式时)。

  • 不能有非 trivial 构造函数、析构函数或拷贝赋值运算符的成员(C++11 起可含 std::string 等,但需手动管理生命周期)
  • 推荐搭配 enum class 手动标记当前有效字段,例如:enum class Type { INT, FLOAT, PTR };
  • 若需类型安全,优先考虑 std::variant(C++17),它内部用 union + tag 实现,但帮你管住了读写逻辑

用 union 节省内存的关键:只在明确控制生命周期的场景下出手

节省内存不是靠“用了 union 就省”,而是靠**避免为多个互斥状态预留独立空间**。典型适用场景:解析二进制协议、硬件寄存器映射、实现紧凑的 AST 节点、自定义容器中的小对象优化(SOO)。

例如网络包头中,一个字段可能是 IPv4 地址(uint32_t)或 IPv6 地址(uint8_t[16]),二者永不同时存在:

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

union Addr {
    uint32_t v4;
    uint8_t v6[16];
};

这里 sizeof(Addr) 是 16,而非 sizeof(uint32_t) + sizeof(uint8_t[16]) 的 20。

LLaMA
LLaMA

Meta公司发布的下一代开源大型语言模型

下载
  • 别为了“看起来省”而把本该独立存在的字段塞进 union —— 比如一个类既有 name 又有 id,它们逻辑上共存,就绝不该放 union 里
  • 注意对齐:union 的对齐取各成员对齐要求的最大值,可能因 padding 导致实际省得没预期多
  • 嵌套 union 可进一步压缩,但会显著增加维护成本,慎用

union 和 std::bit_cast / memcpy 的配合才是底层可控的关键

当你需要把一块内存按不同类型解释(比如把 float 的 bit pattern 当作 int 来比较符号位),union 曾是常用手段,但 C++20 前它触发 strict aliasing 规则,属于未定义行为。现在更安全的做法是用 std::bit_cast(C++20)或 memcpy 到 char 数组再 reinterpret_cast。

例如安全地提取 float 的符号位:

int sign_bit(float f) {
    auto bits = std::bit_cast(f);
    return (bits & 0x80000000) ? -1 : 1;
}
  • 旧式 union “类型双关”(type punning)写法:union { float f; uint32_t i; } u = {.f = f}; return u.i; —— 在 GCC/Clang 上常能工作,但标准不保,且 -O2 可能被优化掉
  • std::memcpy 方案兼容所有标准版本,且编译器通常能内联优化,比 union 更可靠
  • 别用 reinterpret_cast(f) —— 这是严格禁止的 aliasing 操作

union 成员的构造与析构必须显式管理

C++11 允许 union 包含类类型成员(如 std::string),但**编译器不会帮你调用构造/析构函数**。你得用 placement new 和显式析构,否则资源泄漏或崩溃几乎必然发生。

例如这个 union:

union Payload {
    int i;
    std::string s;
    Payload() : i(0) {} // 必须提供默认构造,且只能初始化 trivial 成员
    ~Payload() {}       // 析构函数必须为空,否则编译报错
};

要存 string,必须手动构造:

Payload p;
new (&p.s) std::string("hello"); // placement new
// ... 使用 p.s ...
p.s.~basic_string(); // 显式析构
  • 忘记析构 std::string 会导致内存泄漏;重复析构会崩溃
  • switch 成员时,必须先析构旧成员、再构造新成员,顺序不能错
  • 真实项目中,这类逻辑极易出错,建议封装成带 tag 的 wrapper 类,或直接用 std::variant
底层细节容易被忽略的一点:union 的地址和其任意成员的地址相同,但**成员的偏移量始终为 0**。这意味着你不能指望通过指针算术去“跳转”到下一个成员——它根本不存在。所有操作都必须基于你确切知道当前活跃的是谁,以及你是否已正确管理了它的生命周期。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

523

2023.08.02

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

580

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

103

2025.10.23

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1505

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

233

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

87

2025.10.17

switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

544

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

424

2024.03.13

AO3官网入口与中文阅读设置 AO3网页版使用与访问
AO3官网入口与中文阅读设置 AO3网页版使用与访问

本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。

45

2026.02.02

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 55.8万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号