【发布时间】:2020-11-26 09:53:32
【问题描述】:
我正在将一些旧的 c++ 代码从 Visual Studio 2013 更新到 VS2019,并遇到了一个有趣的问题:
有问题的代码使用一个名为 Attrib.h 的类来表示表格单元格中任何可能的数据单元。该数据可以是 bool、int、double、Guid/Uuid、各种类型的几何数据、文本等。因此,Attrib.h 包含许多不同结构的联合,用于表示这些不同的可能数据类型。我在下面包含了一个精简版:
class Attrib
{
public:
union
{
double vDouble;
bool vBool;
struct sUnion
{
#ifdef _WIN64
BYTE Data[24];
#else
BYTE Data[16];
#endif
} vUnion;
union
{
struct
{
INT32 vInt32;
INT32 vInt32High;
};
INT64 vInt64;
};
struct sStr
{
//etc
} vStr;
struct sBin
{
//etc
} vBin;
struct sGeomPt
{
//etc
} vGeomPt;
struct sGeomMultiPt
{
//etc
} vGeomMultiPt;
struct sGeomPoly
{
//etc
} vGeomPoly;
struct
{
Guid vGuid;
};
};
bool UsePool : 1;
bool OwnPtr : 1;
FieldType Type : 8;
//Other data members, excluded for brevity.
#define CONSTRUCT : UsePool(true), OwnPtr(false), Type(FieldTypeNull)
Attrib() CONSTRUCT
{}
}
现在...由于我不明白的原因,每当在 VS2013 中创建 Attrib 实例(例如 Attrib myAttrib)时,编译器都会调用 Guid 类的构造函数(Union 的最后一个成员)。 Guids构造函数如下:
Guid()
{
Q1 = 0;
Q2 = 0;
}
Q1 和 Q2 是无符号 int64 和 Class Guid(Microsoft 的 GUID 的变体)的唯一成员。这具有将类属性联合初始化为 0 的效果,这反过来又掩盖了许多错误。简而言之,未初始化的属性应该是 Null 类型。但在某些地方,由于初始化为零,它们被错误地解释为值为 0 的 double 或 int,或值为 false 的 bool 等。
但是在切换到 VS2019 时,永远不会调用 Guid 构造函数(其余代码未更改,因此我认为这是编译器的“决定”)。结果, Attrib 类的 Union 组件未初始化为 0,而是初始化为大量负数(在整数或双精度数的情况下),在布尔值的情况下为“真”等。这具有取消屏蔽的效果一些以前的错误,最终是一件好事。
但是,我的问题是:
-
编译器在 2013 年调用 Guid 构造函数,然后在 2019 年不再这样做的原因是什么?我没有更改这些类中的任何代码,所以我假设这些是对编译器规则的更改。有什么地方可以读到这个吗?
-
依赖此默认 2013 行为的案例是错误,我正在追踪它们。但是,与此同时,我需要复制 VS2013 构建的默认行为并将 Union 初始化为零,以便可以使用代码。我只是简单地更新了 Attrib.h 的构造函数以调用 vUnion 结构,它具有对所有内容进行零初始化的效果。即:
#define CONSTRUCT : UsePool(true), OwnPtr(false), Type(FieldTypeNull), vUnion()
这完全符合我的需要,而且对于一个经常实例化的类来说似乎没有明显的额外成本。但是有没有更好的方法呢?
【问题讨论】:
标签: c++ visual-studio visual-studio-2019 unions