一个类成员函数的局部静态变量问题


  之前工作中遇到一个问题,就像题目中描述的那样,看起来题目有些拗口复杂,这里解释下,当时遇到的需求需要这样处理:调用某个类对象的某个成员函数时,第一次有具体意义的,其他时候都是保持不变的、无意义的。这个需求可以看做是在调用某成员函数时,第一次进行初始化,其他时候不进行操作,即在首次调用时进行初始化,根据这点,很容易想到c/c++里面的static变量,它的作用是保持变量内容的持久,存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。根据需求,使用static局部变量,写下如下代码:

 1 class T  2 {  3 public:  4     T(const char * pstr):value(pstr){}  5     void Print()const;  6 private:  7     string value;  8 };  9 
10 void T::Print()const
11 { 12     static bool bFirstCall = true; 13     if(bFirstCall) 14  { 15         cout<<"first Call "<<value<<endl; 16         bFirstCall = false; 17  } 18     else
19  { 20         cout<<"not first Call "<<value<<endl; 21  } 22 } 

即在类的成员函数中定义一个局部的静态变量,使得第一次调用进行初始化,用以区分是否是第一次调用,之后运行else分支。运行下面的测试代码,输出结果见下图:

 1 int _tmain(int argc, _TCHAR* argv[])  2 {  3     T t1("Grubby");  4  t1.Print();  5  t1.Print();  6 
 7     T t2("Moon");  8  t2.Print();  9  t2.Print(); 10 
11     return 0; 12 }

通过输出可以看到,t1得到了想要的结果,但是两次t2.Print()都打印 "not first Moon",这说明此时 bFirstCall 还是false。于是在Print函数中打印bFirstCall地址的代码:

 1 void T::Print()const
 2 {  3     static bool bFirstCall = true;  4     printf("addr of bFirstCall is %x\n", &bFirstCall);  5     if(bFirstCall)  6  {  7         cout<<"first Call "<<value<<endl;  8         bFirstCall = false;  9  } 10     else
11  { 12         cout<<"not first Call "<<value<<endl; 13  } 14 }

再次运行输出如下:

看到四次调用Print函数时打印的bFirstCall的地址相同,这说明类成员函数中的局部静态变量同样属于此函数,而不属于某个对象,不会因为重新定义一个t2对象,第一次调用 t2.Print()时 bFristCall 是 true,不管是哪个T类对象,只在第一次调用 Print()时,bFirstCall == ture。于是无奈对程序进行了修改,将bFristCall定义为类的静态成员,每次构造函数是将其重置为true:

 1 class T  2 {  3 public:  4     T(const char * pstr):value(pstr){ bFirstCall = true;}  5     void Print()const;  6 private:  7     string value;  8     static bool bFirstCall;  9 }; 10 bool T::bFirstCall; 11  
12 void T::Print()const
13 { 14     if(bFirstCall) 15  { 16         cout<<"first Call "<<value<<endl; 17         bFirstCall = false; 18  } 19     else
20  { 21         cout<<"not first Call "<<value<<endl; 22  } 23 }

运行测试代码可以得到想要的结果:

但是这里又出现了新的问题,即每次构造函数是将bFirstCall重置为true时,如果新定义一个对象,并且没有调用Print()函数,那么再次调用之前定义对象的Print()函数,会产生与预期相反的结果,考虑如下测试代码:

 1 int _tmain(int argc, _TCHAR* argv[])  2 {  3     T t1("Grubby");  4  t1.Print();  5  t1.Print();  6 
 7     T t2("Moon");  8  t1.Print();  9 
10     return 0; 11 }

运行输出如下:

避免这种情况,目前只能保证顺序的对每个对象进行类似Print这样函数的初始化调用,还没有想到好的解决办法。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM