27 January 2023

C++ 核心指南目录

“Avoid “naked” union’s”

理由

“裸露” union 指的是那种无从知晓其保存的到底是什么类型的数据。所以,程序员得自己进行记录。裸露 union 容易导致错误。

坏例子

union Value {
    int x;
    double d;
};

Value v;
$$c181-union$$
v.d = 987.654;  // v holds a double
cout << v.d;
987.654

目前,暂时没什么问题,但是很容易误用:

union Value {
    int x;
    double d;
};

Value v;
cout << v.x << '\n';    // BAD, undefined behavior: v holds a double, but we read it as an int
-564582640

注意,这里没有任何显示的类型转换。最后打印出的数据是 -564582640,这个数据是 987.654 这个浮点数据的bit位的整型表示。这里的类型错误是不可见的,很容易被忽略。

以下代码把整型 123 的bit位数据以浮点型输出:

union Value {
    int x;
    double d;
};

Value v;
v.x = 123;
cout << v.d << '\n';    // BAD: undefined behavior
1.06312e-311

替代方案

把 union 封装到有类型信息的类中。

使用 C++17 variant 类型 (在 <variant> 中定义的)

variant<int, double> v;
v = 123;        // v holds an int
int x = get<int>(v);
v = 123.456;    // v holds a double
auto w = get<double>(v);
cout << w;
123.456

如果你存进了 int, 但是想得到一个 double 就会出错:

variant<int, double> v;
v = 123;        // v holds an int
auto w = get<double>(v);
terminate called after throwing an instance of 'std::bad_variant_access'
  what():  std::get: wrong index for variant