019 C++的union类型


作者Lou Xiao, deepseek创建时间2025-04-02 15:08:35更新时间2025-04-02 15:08:35

1. Union 的基本概念

1.1 定义

  • Union(联合体)是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型
  • 语法:union UnionName { member_list };
  • 所有成员共享同一块内存空间

1.2 与结构体的区别

特性UnionStruct
内存使用共享内存每个成员有独立内存
大小最大成员的大小所有成员大小之和(考虑对齐)
同时访问只能访问一个活跃成员可同时访问所有成员

2. Union 的基本用法

2.1 声明与定义

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 union Data {
2 int i;
3 float f;
4 char str[20];
5 };
6
7 Data data; // 声明union变量

2.2 成员访问

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 data.i = 10; // 使用int成员
2 cout << data.i;
3
4 data.f = 220.5; // 现在使用float成员
5 cout << data.f; // 此时data.i的值已被覆盖

2.3 大小计算

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cout << sizeof(Data); // 输出20,因为char str[20]是最大成员

3. Union 的高级特性

3.1 匿名Union (C++11)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct Widget {
2 enum class Type { INT, FLOAT, STRING } type;
3
4 union {
5 int i;
6 float f;
7 char s[20];
8 };
9 };
10
11 Widget w;
12 w.type = Widget::Type::INT;
13 w.i = 10; // 直接访问匿名union成员

3.2 带有构造函数的Union (C++11)

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 union U {
2 string s; // 有非平凡构造函数的成员
3 int n;
4
5 U() : s("default") {} // 必须提供构造函数
6 ~U() {} // 必须提供析构函数
7 };

3.3 受限Union (C++11)

  • 当union包含有非平凡特殊成员函数的类型时:
  • 默认构造函数被删除
  • 必须自定义构造函数和析构函数
  • 不能包含引用成员

4. Union 的应用场景

4.1 内存优化

  • 当需要存储多种类型但不会同时使用时
  • 在内存受限环境中节省空间

4.2 类型转换

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 union Converter {
2 float f;
3 unsigned int u;
4 };
5
6 Converter c;
7 c.f = 3.14f;
8 cout << hex << c.u; // 输出浮点数的二进制表示

4.3 变体类型实现

  • 结合enum实现简单的变体类型
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct Variant {
2 enum { INT, FLOAT, STR } type;
3 union {
4 int i;
5 float f;
6 char s[20];
7 };
8 };

5. Union 的注意事项

5.1 活跃成员

  • 任何时候只有一个成员是"活跃的"(存储了有效值)
  • 访问非活跃成员是未定义行为(UB)
  • 需要额外信息(如enum)来跟踪当前活跃成员

5.2 内存对齐

  • Union的大小会按照最大成员的对齐要求进行对齐
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 union AlignDemo {
2 char c; // 1字节
3 double d; // 8字节
4 }; // 大小可能是8而不是9

5.3 与C的兼容性

  • C++中的union比C中的更严格
  • C允许union包含结构体,C++进一步允许包含类(但有特殊要求)

6. C++17中的std::variant

6.1 Union的现代替代品

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 #include <variant>
2 using var_t = std::variant<int, float, std::string>;
3
4 var_t v = 42; // 当前存储int
5 v = 3.14f; // 现在存储float
6 v = "hello"; // 现在存储string

6.2 与Union的比较

特性Unionstd::variant
类型安全不安全安全
活跃成员跟踪需要手动自动
异常安全
可包含类型有限制几乎任何可复制类型
性能更高稍低

7. 最佳实践

  1. 优先考虑使用std::variant,除非有严格的性能需求
  2. 如果使用union,总是配合一个类型标签(enum)来跟踪活跃成员
  3. 避免在union中存储需要复杂构造/析构的类型
  4. 对union进行封装,提供类型安全的接口
  5. 注意跨平台问题,特别是涉及类型转换时

8. 示例代码

8.1 类型安全的Union封装

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 class SafeUnion {
2 public:
3 enum Type { INT, FLOAT, STRING };
4
5 SafeUnion(int i) : type(INT) { data.i = i; }
6 SafeUnion(float f) : type(FLOAT) { data.f = f; }
7 SafeUnion(const char* s) : type(STRING) { strcpy(data.s, s); }
8
9 Type getType() const { return type; }
10
11 int getInt() const {
12 if (type != INT) throw std::runtime_error("Not an int");
13 return data.i;
14 }
15 // 类似getFloat(), getString()...
16
17 private:
18 Type type;
19 union {
20 int i;
21 float f;
22 char s[20];
23 } data;
24 };

8.2 Union在协议解析中的应用

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 struct NetworkPacket {
2 uint8_t type;
3 union {
4 struct { uint32_t ip; uint16_t port; } connection;
5 struct { char filename[256]; } fileRequest;
6 struct { uint32_t chunks[8]; } dataChunk;
7 } payload;
8 };
文章目录