C++關於一個函式中new記憶體洩露的列子

gaopengtttt發表於2016-08-17
首先明白幾個基礎
1、函式按值傳遞和按值返回的時候都會呼叫複製建構函式
2、一般在函式體內定義的棧變數是不能返回其地址或者引用給主調函式的,因為在函式結束的時候這些棧變數將釋放
3、可以使用new的方式建立堆記憶體的方式,然後返回引用或者指標,因為new這種方式建立的堆記憶體並不隨函式的結束而結束,
     而指標變數釋放但是指標本生的值已經返回。同時也可以按值放回,但是這種情況下將可能出現記憶體洩露
來看下面的程式碼

點選(此處)摺疊或開啟

  1. /*************************************************************************
  2.     > File Name: testcc.cpp
  3.     > Author: gaopeng
  4.     > Mail: gaopp_200217@163.com
  5.     > Created Time: Thu 01 Sep 2016 09:06:53 PM CST
  6.  ************************************************************************/

  7. #include<iostream>
  8. using namespace std;


  9. class testa
  10. {
  11.         private:
  12.                 int i;
  13.         public:
  14.                 testa(const int m){
  15.                         cout<<"create a object\n";
  16.                         i=m;
  17.                 }
  18.                 const int& geti() const {
  19.                         return i;
  20.                 }
  21.                 testa(const testa& m ){
  22.                         cout<<"copy funcation\n";
  23.                         i=m.i;
  24.                 }
  25.                 ~testa(){
  26.                         cout<<"discard a object\n";
  27.                 }
  28.                 testa operator=(const testa& c)
  29.                 {
  30.                         cout<<"= funcation\n";
  31.                         i = c.i;
  32.                 }

  33. };

  34. testa func()
  35. {
  36.         cout<<"in func function\n";
  37.         //testa p(10);
  38.         testa* p = new testa(1);
  39.         cout<<p<<endl;
  40.         cout<<"end func\n";
  41.         return *p;
  42. }


  43. int main(void)
  44. {
  45.         testa m = func(); //copy
  46.         cout<<&m<<endl;
  47.         cout<<m.geti()<<endl;
  48.         return 0;
  49. }
程式說明:
這裡testa* p = new testa(1);建立一塊堆記憶體
這裡return *p;按值返回,按值返回會呼叫複製建構函式給值賦予給新建個物件m
程式結束後呼叫m的解構函式,但是這裡new出來的記憶體空間已經沒有可以指向的指標
因為p已經釋放,而返回的是*p,這塊記憶體已經洩露。我們跑一下看看:
in func function   --呼叫func函式
create a object   --new建立的testa的堆記憶體 testa* p = new testa(1);
0x1914010        --new的地址 cout<<p<<endl;
end func           --結束func函式 cout<<"end func\n";
copy funcation   --按值返回撥用複製建構函式,將值賦予給新的變數m testa m = func();
0x7fffb9c438a0  --新物件m的地址cout<<&m<<endl;
1
discard a object  --解構函式釋放棧物件m的空間

這裡我們發現new的堆記憶體空間沒有被析構,那麼記憶體已經洩露。
那麼我們怎麼不大量改變程式的情況下來消除這種問題呢
當然是使用指標或者引用來返回

點選(此處)摺疊或開啟

  1. testa* func()
  2. {
  3.         cout<<"in func function\n";
  4.         //testa p(10);
  5.         testa* p = new testa(1);
  6.         cout<<p<<endl;
  7.         cout<<"end func\n";
  8.         return p;
  9. }


  10. int main(void)
  11. {
  12.         {
  13.                 testa* m = func(); //copy
  14.                 cout<<m<<endl;
  15.                 cout<<m->geti()<<endl;
  16.                 delete m;
  17.         }
  18.         return 0;
  19. }
這一在main中我把定義m指標到刪除放到了一個block中,這樣在block結束的時候就釋放了m避免了空指標的存在。
下面是引用

點選(此處)摺疊或開啟

  1. testa& func()
  2. {
  3.         cout<<"in func function\n";
  4.         //testa p(10);
  5.         testa* p = new testa(1);
  6.         cout<<p<<endl;
  7.         cout<<"end func\n";
  8.         return *p;
  9. }


  10. int main(void)
  11. {
  12.         {
  13.                 testa& m = func(); //copy
  14.                 cout<<&m<<endl;
  15.                 cout<<m.geti()<<endl;
  16.                 delete &m;
  17.         }
  18.         return 0;
  19. }
同樣main中的這個程式塊是為了避免空引用
輸出如下:
in func function  
create a object
0x1989010
end func
0x1989010   
1
discard a object

可以看到地址都相同,最後的解構函式是我呼叫delete執行的。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2123621/,如需轉載,請註明出處,否則將追究法律責任。

相關文章