编程中一些比较容易出错的地方

全局变量

经验告诉我们,能不使用全局变量就不要使用全局变量,但是全局变量的一些好处又诱使我们去用它。但是是如果不注意,会出现一些很棘手的问题。使用全局变量,一定慎重考虑全局变量的初始化顺序问题。下面几种情况会出现问题,但是比较隐蔽:

全局变量相互依赖

下述代码在某些机器上,Y的值可能是不定的。

static const int X = 10;
static const int Y = X;

实际项目中的例子

为了管理方便,字体的颜色通常都是集中放到一个类或者命名空间中。如下(假设此文件为defs.h):

namespace VeryLongNameSpace
{
	int COLOR_WHITE[] = {255, 255, 255};
	int COLOR_BLACK[] = {0, 0, 0};
}

在x.cpp中使用的时候,由于直接使用VeryLongNameSpace::COLOR_WHITE太长了,所以就重新定义了一下

static int COLOR_WHITE[] = VeryLongNameSpace::COLOR_WHITE;

这样在台式机上运行正常,但是到了手机上运行,显示出来文字的图像就有问题。究其原因,还是全局变量初始化化顺序不定导致的。

要在x.cpp中重新定义,正确的做法有二:一是使用宏,二是使用函数

// 方式一
#define COLOR_WHITE VeryLongNameSpace::COLOR_WHITE
// 方式二
inline int[] COLOR_WHITE()
{
        return VeryLongNameSpace::COLOR_WHITE;
}


更加隐蔽的依赖

一般情况下,使用函数可以规避全局变量相互依赖的问题,但是还有一种比较隐蔽的情况,即函数依赖于某个在main中才初始化的对象。

实际项目中的例子

在手机应用开发过程中,为了适应不同屏幕,一种做法是根据屏幕尺寸对坐标进行转换,但是像下面这样的使用方式就会有问题。

首先有定义:

class Device
{
	public:
		static void Init()
		{
			m_mat = new Matrix;
			// 其它初始化
		}
		
		static Point tranform(const Point& pt)
		{
			return m_mat*pt;
		}
		
		private:
			Matrix m_mat;
}

其次,在main中调用获取到设备信息后,调用

Device::Init()

然后在y.cpp中定义了全局变量

static const Point MY_POINT = Device::Transform(Point(50, 30));

这个MY_POINT的值也是不确定的。严重的情况下,直接出现莫名其妙的崩溃。

这种情况下,用上一种情况所用的两种方法都可以很好地解决。

函数状态依赖于调用

局部静态变量

局部静态变量的使用有一些好处,比如可以保存状态,而且让此状态的封装性比较好。但是由此带来的问题有时也是很严重的,比如类ObjectA中的一个方法中具有局部静态变量,那么不同的对象在调用此方法时是具有依赖的。

class ObjectA
{
	public:
		int foo()
		{
			static int x = -1;
			int y = x;
			if(-1 == x)
			{
					x = 8;
			}
			
			return y;
		}
}

ObjectA的不同对象在调用此方法的时候是会相互依赖的。另外,类的非静态成员变量也会造成对象间的相互依赖。

状态没有重置(重新初始化)

对于一些容器,比如vector,在使用之前尽量要将其重置,即clear/reserve等。实际项目中,在一个单体的某方法中使用了vector::push_back,并且这个方法一天只会调用一次,在push_back之前没有做clear的工作。当程序不关闭,第二天再次调用到此方法时,就出现问题了。

 

你可能感兴趣的:(编程陷阱)