CppCoreGuidelines C.181 避免裸露的 union
27 January 2023
“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