C++ union如何节省内存_C++共用体内存共享机制与使用限制

共用体通过共享内存节省空间,所有成员共用同一内存区域,大小由最大成员决定,适用于变体类型、硬件映射等场景,但需手动管理当前激活成员,不能含非平凡构造的类,现代C++推荐使用std::variant替代。

在C++中,union(共用体)是一种特殊的数据类型,允许在相同的内存位置存储不同的数据类型。它通过内存共享机制实现节省内存的目的,适用于某些特定场景下的内存优化。下面详细说明其工作原理和使用限制。

内存共享机制:同一块内存被多个成员共用

共用体的所有成员共享同一段内存空间,其大小等于最大成员所需的字节数。这意味着任何时候只能有一个成员处于有效状态。

例如:
union Data {
    int i;
    float f;
    char str[8];
};

这个 Data 共用体的大小为 8 字节(由 char str[8] 决定),无论你使用哪个成员,都使用这 8 字节中的同一区域。

  • 当你给 i 赋值后,再读取 f,结果是未定义的(位模式解释不同)
  • 共用体不会自动记录当前激活的是哪个成员,程序员必须自行管理

如何节省内存:避免为多个互斥字段分配独立空间

在资源受限或需要高效存储的场景下,共用体非常有用。典型应用包括:

  • 表示一种“变体”类型,比如某个变量在不同情况下可能是整数、浮点数或字符串指针
  • 硬件寄存器映射:同一组寄存器在不同模式下代表不同含义
  • 网络协议解析:某些字段根据标志位解释为不同类型
对比结构体:

如果使用 struct 存储上述 Data 类型的三个字段,总大小至少是 int + float + char[8] 的对齐总和,通常远大于 8 字节。而 union 只需最大成员的空间,显著减少内存占用。

使用限制与注意事项

尽管能节省内存,但共用体有严格的使用约束:

  • 不能包含具有非平凡构造函数、析构函数或拷贝控制的类类型(如 std::string、std::vector)
  • C++11 起支持带构造函数的类,但需手动管理生命周期(使用 placement new 和显式析构)
  • 访问非当前写入的成员属于未定义行为,编译器不作检查
  • 无法继承其他类,也不能作为基类
  • 不支持 static 成员变量

为安全使用共用体,常配合一个枚举标记当前状态:

struct SafeData {
    enum Type { INT, FLOAT, STRING } type;
    union {
        int i;
        float f;
        char str[8];
    };
    
    void setInt(int val) {
        type = INT;
        i = val;
    }
    // 使用前检查 type 判断当前有效成员
};

基本上就这些。共用体适合对内存敏感且能严格控制状态切换的底层编程场景,但现代C++更推荐使用 std::variant(C++17)来替代,它提供了类型安全的多态存储,虽然略有运行时开销,但更安全易用。