關於c++中一些指針問題的思考

 

昨天爲了對c#的一些機制做更深的理解,特別用了c++的實現與之作對比。這不,c#沒搞出大名堂,c++卻揪出了一塊煩心的事情:

還是昨天那個代碼

 1

 

原本設計SendPersonByReference函數的功能就是傳進一個對象的引用(指針和&引用都算,泛化的引用),改變該引用引用的對象。像上面那樣設計好,自我感覺還挺良好,先造個輔存tmp,記錄原對象的地址,接着析構delete,再將p指向新new的對象。一切ok(ps:運行的機子是dell的商用機,vista sp1英文版,vs2008 英文版) 運行結果如下圖:

 

 2

pdpd的回住所,突發奇想,想到再運行下代碼,於是在自己的小黑(win7 7000 英文版,vs2005)下balabala的敲好代碼再運行,ft程序直接崩潰。。。。。。

剛開始想不通,很鬱悶,但是後來仔細想想,卻發現自己在c++ 指針上犯了一個特大的煞筆級別的錯誤:踩到了“棧上動態分配堆內存”的大地雷。

地雷p指針傳入,用p new了一塊堆內存,void的返回值。函數體一旦結束,拜拜,指針p被銷燬了,那塊可憐內存死在荒野無人問津,memory leak

內存問題先談到這裏,就單單談功能的實現,其實我原先設計的函數是向下面這樣的(更加煞筆)

void SendPersonByReference(Person *p)

{

                p->personAge = 555;     

                p = new Person("Nikki", 10000);

}

運行完出來結果:p指向的對象沒變….首先,我總結爲內存肯定是泄漏了,p在第二句掉頭指向新new的對象。於是我就把代碼改成了剛開始上面的代碼,一運行,哈哈,在dell機上ok,以爲萬事大吉!誰知在回家後卻發現代碼重大的隱患

 

仔細分析:

1.       針對最開始的代碼,首先就是出現了棧上動態分配堆內存的大忌(詳見上面的地雷)

2.       從函數設計和功能上來說,我傳入一個對象指針p,其實也只是對指針p的拷貝,函數體中實際在做的操作其實全都是p

 

3


 

p = new Person("Nikki", 10000);

這一句其實只是把p‘指向新得到的對象,而不是改變了真正需要改變的p。所以,就算你沒有memory leak,它的運行的結果也不是你原先設計想要的答案。

3.       應該如何設計呢?

 void SendPersonByReference(Person **p)

{

 

    *p = new Person("Nikki", 10000);

    }

4

4.       最後一個疑問

爲什麼原先的設計在dell的機器上運行的時候,錯誤的設計卻得到了正確的答案,而在別的機器上運行又是錯誤的呢?

這個問題我也沒想特別的明白,windows以及編譯器內部的處理機制也不是特別的清楚,估計應該是

void SendPersonByReference(Person *p)

{

          Person *tmp = p;

          p->personAge = 555;

          delete tmp;

         // p = new Person("fds",234);

  p = new Person("Nikki", 10000);

}

5

 

通過delete tmp我們將pp‘,tmp共同指向的內存區域“回收”了,pp’以及tmp成爲了傳說中的野指針。(事實上它們亂指一氣嗎?) 。通過p = new Person("Nikki", 10000);  p‘指向了新的內存區域,按照在dell上的運行結果反推回去,我們可以知道,新分配的內存其實就是原先被delete的內存區域,不然爲何p(不是p)會指向新開闢的內存區域~。根據我的推斷,也就是說編譯器以及os將最新回收的內存立即又分配給了新的請求(new new Person("Nikki", 10000) ),具體vista以及編譯器的內部實現,水平太差,有待繼續深入研究。

 

爲了進一步的驗證我的臆測,我修改代碼:

void SendPersonByReference(Person *p)

{

          Person *tmp = p;

          p->personAge = 555;

          delete tmp;

          p = new Person("damn",1234);

  p = new Person("Nikki", 10000);

}

運行結果和前面的運行結果一樣,也就是說在函數棧沒被destroy之前,p指向了“new Person("damn",1234);”的地址,p‘指向“p = new Person("Nikki", 10000);”指向的地址。當然了,函數體結束以後,遺漏了2塊堆內存,一塊(new Person("Nikki", 10000);)真的是泄露了,另一塊(p = new Person("damn",1234);)歪打正着被原先的實參p指着。

 

總結:
依靠野指針未確定的行爲進行編程是極其有害和邪惡的,我們當然應該避之不及。C++給了程序員足夠的信任和自由去操作內存和系統,但也另外給了我們一顆顆隱患的地雷,繼續修煉吧devx!以上有錯誤的地方的,還肯請大牛小牛們指點,俺現在水平就這麼點,想到的全寫了。止筆於此,該看c#去了…….

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章