c++ union使用笔记
C++联合(union)是一种特殊的数据结构,允许在相同内存位置存储不同的数据类型,其核心价值在于 节省内存空间 (所有成员共享同一块内存)。以下是联合的详细说明和应用示例:
一、联合的简单使用
特点:
- 所有成员共享同一块内存(大小为最大成员的大小)
- 同一时间只能使用一个成员
- 默认访问权限为
public
示例:
cpp
union NumericData {
int i;
double d;
char c;
};
int main() {
NumericData data;
data.i = 42; // 存储整数
std::cout << data.i << "\n"; // 输出 42
data.d = 3.14; // 覆盖内存,存储双精度浮点数
std::cout << data.d << "\n"; // 输出 3.14
// 注意:此时访问 data.i 将得到无意义的值!
return 0;
}
二、联合与枚举结合
核心思想:通过枚举标记联合当前存储的数据类型,避免错误访问。
示例1:
cpp
// 定义数据类型标签
enum class DataType { INT, DOUBLE, CHAR };
struct DataContainer {
DataType tag; // 类型标记
union {
int i;
double d;
char c;
};
};
int main() {
DataContainer dc;
dc.tag = DataType::INT;
dc.i = 100;
// 安全访问:先检查类型标记
if (dc.tag == DataType::INT) {
std::cout << dc.i << "\n"; // 输出 100
}
dc.tag = DataType::DOUBLE;
dc.d = 2.718;
// 错误示例:未检查标记直接访问将导致未定义行为
return 0;
}
示例2:
cpp
#include <iostream>
#include <string>
enum class DataType { INT, DOUBLE, STRING };
struct Variant {
DataType type;
union {
int i;
double d;
std::string s;
};
// 构造函数
Variant(int val) : type(DataType::INT), i(val) {}
Variant(double val) : type(DataType::DOUBLE), d(val) {}
Variant(const std::string& val) : type(DataType::STRING) {
new (&s) std::string(val); // Placement new 构造字符串
}
// 析构函数
~Variant() {
if (type == DataType::STRING) {
s.~basic_string(); // 手动析构字符串
}
}
// 拷贝构造函数
Variant(const Variant& other) : type(other.type) {
switch (type) {
case DataType::INT: i = other.i; break;
case DataType::DOUBLE: d = other.d; break;
case DataType::STRING: new (&s) std::string(other.s); break;
}
}
// 赋值运算符
Variant& operator=(const Variant& other) {
if (this != &other) {
if (type == DataType::STRING) s.~basic_string();
type = other.type;
switch (type) {
case DataType::INT: i = other.i; break;
case DataType::DOUBLE: d = other.d; break;
case DataType::STRING: new (&s) std::string(other.s); break;
}
}
return *this;
}
};
三、匿名联合(Anonymous Union)
特点:
- 没有名称,直接访问成员
- 常用于结构体或类内部简化访问
- C++11 起允许包含非平凡类型(如
string
,但需谨慎使用)
示例:
cpp
struct Data {
enum { INT, FLOAT } type;
union { // 匿名联合
int i;
float f;
};
};
// 使用示例
Data d;
d.type = Data::INT;
d.i = 42; // 直接访问匿名联合成员
四、关键注意事项
- 内存覆盖:修改一个成员会影响其他成员的值。
- 类型安全:必须手动跟踪当前有效成员(通常结合枚举)。
- 构造/析构:C++11 起支持含有非平凡类型的联合,但需显式管理生命周期。
- 应用场景 :
- 协议解析(如网络数据包)
- 硬件寄存器映射
- 内存敏感型应用(嵌入式系统)
五、C++17 扩展:std::variant
对于需要更安全的类型存储,推荐使用 std::variant
(C++17 引入):
cpp
#include <variant>
#include <string>
int main() {
std::variant<int, double, std::string> data;
data = 42; // 存储 int
data = "Hello"; // 存储 string
// 自动跟踪当前类型,无需手动标记
return 0;
}