12月 29

关于C++指针的一些思考

长时间看学术问题,很少关注编程序时的所谓技术问题了,但是今天碰到了一个有趣的问题,引起了我的一些思考。

其实指针这个玩意应该可以被算作C++被人诟病的一个非常主要的原因了吧。读了博很少编程序了,C++真的要用起来有些东西还是不太了解。

今天的程序具体如下:

class CWord
{
public:
	string word;
	string type;
    //这里有一些其他成员
	
    //下面这两个继承自CStatic,与一些复杂的界面操作有关系
	CMyStatic * p_stc_word;
	CMyStatic * p_stc_group;

	void DestroyUI()
	{
		if(p_stc_word)
			delete p_stc_word;
		
		if(p_stc_group)
			delete p_stc_group;

		p_stc_word = NULL;
		p_stc_group = NULL;
	}

	CWord()
	{
		Init();
	}

	~CWord()
	{
         //关键的话在这里,这个导致了严重的错误
         DestroyUI();
	}

//另外有一个类,里面有一个CWord的数组
class CSentence
{
private:	
	vector < CWord > _vsen;
public:
    CWord & get_element(int i) {return _vsen[i];}   //为了尽量简化,就不检测越界之类的了,只是一个示例而已
}sen;

//然后悲剧发生了
//有一个函数 A
//调用了A之后,cw被销毁了,于是调用了~CWord,于是_vsen[0]中的两个CMyStatic被删掉了……
//这个错误让我想了半天,囧
void A()
{
    CWord cw = sen.get_element(0);
}

下面记录一下对以上内容的几点思考:

​1. 首先原来的程序如果改成 CWord & cw = sen.get_element(0);这样的话,其实cw就不会被销毁了,也不会出现错误了,但是当时没有想到,太麻痹大意

​2. 其实这样的get_element本身就是错误的,也是随手一写。我觉得应该改成get_element_text直接获取CWord里面的word成员更好一写,这样可以避免类的拷贝,因为我的目的本来就是只要word的内容,却把整个CWord复制出来了。

3.唉,关于指针的销毁,这个真是令人头疼。其实究其根本原因,我认为是我错误的在析构函数中调用了DestroyUI,这样导致了析构函数不可控。所以如果一旦存在CWord类的复制,很有可能导致两个CMyStatic在莫名其妙的情况下被删掉。下面有几种解决方案,都是水木上的人讨论的:

方案1:谁产生谁销毁,CMyStatic * 应该都由CWord产生,并有CWord销毁。但是事实上这样很难弄,因为我这个里面的CMyStatic其实是动态控件,和界面之间有非常复杂的交互,如果CWord自己创建CMyStatic,那么每次拷贝就要产生新的CMyStatic,把旧的CMyStatic删掉。但是事实上,sen._vsen里面每一个CWord之间是有依存关系的,他们在界面上依次按前后顺序显示CMyStatic,如果其中一个CMyStatic被改动了,其他所有的都要重新显示,这样会导致界面不停地闪烁。而且CMyStatic在界面上的位置会动态变化,也不好计算。

方案2:把析构函数中的DestroyUI拿掉,在外面调用DestroyUI。我现在把程序改成这样了,唉,这样其实也很容易出错。因为每一次界面的复杂操作都会伴随着CMyStatic控件的删除和重建,需要非常carefully coding!很有可能会漏删或者多删。本着宁可内存泄露也不可多删的原则就这样将就了吧。

方案3:有人说用shared_ptr,没用过~查了一下,应该可行。感觉应该也不方便

综上所述,算是体会到了C++的程序一旦涉及了指针,就是一个真正的无底洞。如果指针+多线程,那真的是灾难。难怪别的程序要自动垃圾回收!Java也不是一无是处的哈哈。