据我理解有关联合的C和C ++标准,如果我尝试访问与实际写入的字段不同的联合的特定字段,则在技术上是未定义的行为。最近我一直在审查其他人编写的旧代码,类似于以下内容:
union myunion {
float myfloat;
unsigned int myuint;
};
myunion a;
a.myfloat = 1.01;
myunion b = a;
简而言之,我试图找出以这种方式在union上使用赋值运算符实际上是明确定义的行为。当我自己编写这样的代码时,我会努力存储union实例主动使用的字段类型,并确保我只读取或写入此值。我猜测使用上面的赋值运算符可能只会导致按位复制(因为在此示例中字段具有相同的大小),因为逐步调试调试器中的代码表明这就是正在发生的事情。这段代码一直表现出微妙的错误,所以我很想知道UB意义上是否存在任何本质上存在风险的问题,直接通过这种方式将联盟分配给另一个联盟。
答案 0 :(得分:2)
正如您所期望的那样。行为是明确定义的。
b现在具有与myfloat值相同的值1.01。分配是按位的。如果你想以“安全”的方式比较a和b,你可以进行逐位比较。 (在float成员上使用operator==
并不是那么安全,部分原因是如果其中一个实际上不包含浮点数,那么它是UB,部分是因为比较浮点数的问题。实际上并没有为联合自动定义相等性,因此您必须编写一个重载。
联盟中始终只有原始类型,允许分配工作。唯一的问题是,如果类型可以是指针,并且您在某处管理该指针。然后,如果你有两个你的联盟实例持有这个指针,你必须要小心。 (但是如果你甚至有一个包含指针的常规变量,这也适用。)
答案 1 :(得分:2)
在pre-C ++ 11中,union
只能包含POD(或类似的东西) - 这些限制的设计使得按位复制可以正常工作。在C ++ 11中,一些限制已被解除,但如果违反旧的限制,则删除复制和赋值(除非您自己定义运算符)。