在向量类中,我们有一些奇怪的异常行为。它教会了我们一个宝贵的教训。
class Vector3D
{
float x, y, z, w;
public:
Vector3D( float ax, float ay, float az, float aw )
: x(ax), y(ay), z(az), w(aw)
{}
Vector3D( float ax, float ay, float az ) // for when you don't care about w
: x(ax), y(ay), z(az)
{}
void Assign( const Vector3D& rhs )
{
x = rhs.x;
y = rhs.y;
z = rhs.z;
w = rhs.w;
}
bool operator==( const Vector3D& o )
{
return (x==o.x && y==o.y && z==o.z && w==o.w);
}
// lots more stuff
}
int main()
{
Vector3D a(1.0f,2.0f,3.0f);
Vector3D b(4.0f,5.0f,6.0f);
a.Assign(b);
bool result=(a==b); // Expected: true. Actual: false, sometimes
}
一段时间以来,Assign
函数似乎存在错误。我们将使用它将一个向量的值复制到另一向量,但是稍后在代码上将无法匹配我们知道应该相同的点。设置了数据断点,但未命中。头被划伤了。最终,我们在Assign
的末尾添加了代码,该代码立即调用operator==
来检查两个向量是否相同...是否相同。
出了什么问题?
答案 0 :(得分:4)
The problem was that the second constructor, the one taking just 3 parameters, wasn't initializing w
. We were very concerned about the performance of our code, and in cases where we knew we would only use x
.y
,and z
we didn't want to use any CPU power on the fourth member variable.
Eventually, we ended up seeing an object whose w
happened to contain a pattern of bits corresponding to IEEE NaN. One of the interesting things about those is that when you compare NaN to NaN, the comparison always fails, even if the bit patterns are the same. So our operator==
method, comparing uninitialized w
values, decided that the two were not the same.
Lesson learned: never use uninitialized data.