联合体及其风险
在不同类型之间共享内存
联合体及其风险 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
什么是联合体
union 允许多个成员共享同一块内存。同一时间只有一个成员有效,并且联合体的大小只取决于其最大成员。
#include <iostream>
union Number {
int i;
float f;
};
int main() {
Number n;
n.i = 42;
std::cout << n.i << "\n";
}联合体的大小
由于成员彼此重叠,联合体的 sizeof 等于其最大成员的大小(加上可能存在的对齐填充),而不是所有成员大小之和。
#include <iostream>
union Mix { char c; int i; double d; };
int main() {
std::cout << sizeof(Mix) << "\n"; // size of double (often 8)
}写入一个成员,读取另一个成员
写入一个成员后读取不同的成员是核心风险。这些位会被重新解释,通常会导致未定义行为或产生出人意料的结果。
#include <iostream>
union Bits { int i; float f; };
int main() {
Bits b;
b.f = 1.0f;
std::cout << b.i << "\n"; // reads float bits as int
}仅有一个活动成员
您最后写入的成员是唯一可以安全读取的成员。请自行跟踪哪个成员是“活动”成员;联合体不会记住这一点。
#include <iostream>
union Value { int i; double d; };
int main() {
Value v;
v.d = 3.14; // d is active
std::cout << v.d << "\n";
}带标签的联合体模式
要安全地使用联合体,请将它与一个标签(枚举)配对,用于记录活动成员。这是 std::variant 的手动前身。
#include <iostream>
struct Tagged {
enum { Int, Double } tag;
union { int i; double d; };
};
int main() {
Tagged t; t.tag = Tagged::Int; t.i = 7;
if (t.tag == Tagged::Int) std::cout << t.i << "\n";
}读取正确的成员
读取前请始终根据标签进行分支判断。读取错误的成员会产生垃圾值。
#include <iostream>
struct Tagged {
enum { Int, Double } tag;
union { int i; double d; };
};
void print(const Tagged& t) {
if (t.tag == Tagged::Int) std::cout << "int " << t.i << "\n";
else std::cout << "double " << t.d << "\n";
}
int main() { Tagged t{Tagged::Double}; t.d = 2.5; print(t); }非平凡成员
将带有构造函数或析构函数的成员(例如 std::string)放入联合体,需要手动进行构造和析构。这很容易出错,也是应优先使用 std::variant 的另一个原因。
匿名联合体
匿名联合体没有名称;它的成员可以直接访问。它在结构体中很实用,但同样适用活动成员规则。
#include <iostream>
struct Packet {
int kind;
union { int code; char letter; };
};
int main() {
Packet p; p.kind = 1; p.code = 99;
std::cout << p.code << "\n";
}联合体为何存在风险
风险总结:
- 不会记住哪个成员处于活动状态。
- 读取非活动成员属于未定义行为。
- 非平凡类型需要手动管理生命周期。
联合体仍然有用的场景
联合体在底层工作中仍然很有用:重新解释字节、在内存紧张的嵌入式代码中节省内存,或匹配固定的二进制布局。对于日常的“几种类型中的一种”数据,请优先选择更安全的替代方案。
迈向 std::variant
std::variant 是一种类型安全的联合体,会替您跟踪活动类型,并在您访问错误类型时抛出异常。本课程的其余部分将对它进行探索。
快速检查
请检查您对联合体的理解。
回顾
您学习了联合体:
- 所有成员共享同一块内存。
- 只有最后写入的成员可以有效读取。
- 使用标签(枚举)跟踪活动成员。
- 在现代 C++ 中,为了安全性请优先使用
std::variant。
常见问题解答
「联合体及其风险」课时是免费的吗?
是的 — 「联合体及其风险」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「联合体及其风险」这节课中我会学到什么?
在不同类型之间共享内存 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「联合体及其风险」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。