C++ 初始化列表踩坑记

class CMyClass {
    CMyClass(int x, int y);
    int m_x;
    int m_y;
};
 
CMyClass::CMyClass(int x, int y) : m_y(y), m_x(m_y)
{
}
你可能以为上面的代码将会首先做`m_y=y`,然后做`m_x=m_y`,最后它们有相同的值。但是编译器先初始化`m_x`,然后是`m_y`,,因为它们是按这样的顺序声明的。结果是`m_x`将有一个不可预测的值。有两种方法避免它,一个是总是按照你希望它们被初始化的顺序声明成员,第二个是,如果你决定使用初始化列表,总是按照它们声明的顺序罗列这些成员。这将有助于消除混淆。

重名是允许的。但是需要记住:

  • 初始化列表中,括号外的是一定成员
  • 然而括号内的可以是构造函数的参数,也可以是成员
  • 如果括号内外是一样的名字,则括号内是构造函数的参数
  • 如果括号内的可以解释为是成员,也可以解释为是构造函数的参数,则优先按参数来解释

看起来很符合直觉,但情况复杂起来的时候……

想写一个三角形类,用来做相交测试一类的东西。因为频繁用到三条边的Bounding Box,于是想在构造时先求出Bounding Box缓存起来。同时,不想把同样的数值储存两次,故在储存Bounding Box时用了引用。

于是很自信的写出来了下面的代码:

class Triangle
{
public:
	Triangle(double Ax, double Ay, double Az, double Bx, double By, double Bz, double Cx, double Cy, double Cz);
 
private:
 
	const double
			Ax, Ay, Az,
			Bx, By, Bz,
			Cx, Cy, Cz;
 
	// declare of references must go before corresponding member
	// or references would be pointed to un-initialized values
	const double
			&ABxMin, &ABxMax,
			&BCxMin, &BCxMax,
			&CAxMin, &CAxMax;
	double xMin, xMax;
};
Triangle::Triangle(double Ax, double Ay, double Az, double Bx, double By, double Bz, double Cx, double Cy, double Cz)
		:
		Ax(Ax), Ay(Ay), Az(Az), Bx(Bx), By(By), Bz(Bz), Cx(Cx), Cy(Cy), Cz(Cz),
		ABxMin(Ax > Bx ? Bx : Ax), ABxMax(Ax > Bx ? Ax : Bx),
		BCxMin(Bx > Cx ? Cx : Bx), BCxMax(Bx > Cx ? Bx : Cx),
		CAxMin(Cx > Ax ? Ax : Cx), CAxMax(Cx > Ax ? Cx : Ax)
{
	xMin = std::min(std::min(Ax, Bx), Cx);
	xMax = std::max(std::max(Ax, Bx), Cx);
}

看起来很靠谱吧,然后运行时发现ABxMin等六兄弟解析出来全是1.2345e-374一类的东西。

开始以为是声明顺序的问题,然而无脑调换顺序之后还是不对。再一分析,发现第一版写的声明顺序对着呢。再换回来,自然还是不对。

继续分析,开始怀疑是ABxMin等六兄弟的初始化列表那里,莫非括号里面编译器给解析的是构造函数的参数?这样的话,后面用到数据的时候,这几个构造函数的参数早不存在了,引用的自然也就是野值了。于是尝试做如下更改:

Triangle::Triangle(double _Ax, double _Ay, double _Az, double _Bx, double _By, double _Bz, double _Cx, double _Cy,
				   double _Cz)
		:
		Ax(_Ax), Ay(_Ay), Az(_Az), Bx(_Bx), By(_By), Bz(_Bz), Cx(_Cx), Cy(_Cy), Cz(_Cz),
		ABxMin(Ax > Bx ? Bx : Ax), ABxMax(Ax > Bx ? Ax : Bx),
		BCxMin(Bx > Cx ? Cx : Bx), BCxMax(Bx > Cx ? Bx : Cx),
		CAxMin(Cx > Ax ? Ax : Cx), CAxMax(Cx > Ax ? Cx : Ax)
{
	xMin = std::min(std::min(Ax, Bx), Cx);
	xMax = std::max(std::max(Ax, Bx), Cx);
}

问题完美解决!

  • 最后更改: 2019/05/27 13:18