C++ 傳值 避免 內存泄漏的一個技巧。[new 了以后,不一定要delete][修正,new后一定delete,沒人幫你釋放的。我錯了,此文章已沒任何意義了]


不用看了,2年前,自己功夫不夠,沒有想清楚,也覺得奇怪呢,忘記了  拷貝構造函數 這一說,結果導致本文 沒有意義了。

其實我根本沒有使用過這個想法的,后來的工作依然是 一個 new 一個delete。

原來以為 C++ 會自動進行類型轉換,我錯了。

 

 

再次聲明,以下是錯誤的,現在經過修正了。紅色為修正后。

----------------------

直接上代碼。其實這是對類 和 指針 理解的一個案例。

#include<stdio.h>
#include<iostream>
using std::endl;
using std::cout;
/*****************
事實證明: 類的一般實例對象 只在所在函數有效,函數結束,這個類實例自動釋放資源。
***************/
#define DEBUG_FUNCTION_LINE() printf("#當前所在函數[%p]  %s() 位於%d行\n",this,__FUNCTION__,__LINE__)


class CServer1{
public:
    int isExit;
public:
    CServer1(){
        this->isExit=0;
        DEBUG_FUNCTION_LINE();
    };

      CServer1(const CServer1&copy){
           DEBUG_FUNCTION_LINE();
           this->isExit=copy.isExit;
      };

~CServer1(){
        this->isExit=1;
        DEBUG_FUNCTION_LINE();
    };
};

////下面這個 函數 是否有缺陷???
CServer1  getPtrFunc (){
    CServer1 *s=new CServer1();
    s->isExit=15;
    return  *s;//如果不用指針,局部變量會有錯誤的。Error 返回局部變量地址 是錯誤的。
//這里錯誤了,函數返回,發生了默認拷貝構造函數,函數內部的 new 沒有釋放掉,倒是新派生出了一個返回值 的類。那個 可以在本函數外圍 自動釋放掉。
}; void func2(){ CServer1 foo; foo=getPtrFunc();//這樣賦值,是否 會存在內存泄漏???當然不會 實際存在內存泄漏了。 std::cout<<" foo->isExist=" << foo.isExit <<endl;//=15 是正常的 //結束后,會執行 釋放 操作的! }; void func3(){ getPtrFunc();//這樣賦值,是否 會存在內存泄漏???當然不會當然會 new了就要delete的 //結束后,會執行 釋放 操作的! }; int main(){ func2();//兩次 析構函數 其實是三次構造,兩次析構,錯誤的。 cout<<"@@@ Func2 完畢。"<<endl; func3();//一次 析構函數 //這個函數證明了 很是OK !太錯誤了,看結果就知道 其實是 兩次構造函數,一次析構函數 cout<<"@@@ Func3 完畢。"<<endl;return 0; }

結果:

#當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::~CServer1() 位於22行 foo->isExist=15 #當前所在函數 CServer1::~CServer1() 位於22行 @@@ Func2 完畢。 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::~CServer1() 位於22行 @@@ Func3 完畢。





 

#當前所在函數[0x7fff5a39ec08] CServer1() 位於17行

#當前所在函數[0x7fbb60c03a00] CServer1() 位於17行

#當前所在函數[0x7fff5a39ec00] CServer1() 位於20行

#當前所在函數[0x7fff5a39ec00] ~CServer1() 位於29行

 foo->isExist=15

#當前所在函數[0x7fff5a39ec08] ~CServer1() 位於29行

@@@ Func2 完畢。

 

#當前所在函數[0x7fbb60c03a10] CServer1() 位於17行

#當前所在函數[0x7fff5a39ec18] CServer1() 位於20行

#當前所在函數[0x7fff5a39ec18] ~CServer1() 位於29行

@@@ Func3 完畢。

 

 

構造函數 和 析構函數 是一一對應的。所以看到上面 沒有少任何一個函數 ,說明 沒有內存泄漏。

我用了一個 new ,但是沒有delete。沒有內存泄漏。

new的類,利用 函數返回值(以前我一直認為返回值 如果是類,必須得用指針呢,其實不用),直接返回類的實例對象,而不是指針,這樣,new出來的就不需要delete,也會自然調用 析構函數了。

 

哈哈,,我好像 是 一個 小學生 突然發現 吸鐵石 S N 互相吸引 ,SS NN互相排斥 一樣。。。[果然跟小學生似的]

 

 突然又想 反着來,返回一個指針 類型的,必須 delete 才能避免內存泄漏。但是 發現 使用函數返回值 我錯了一次。。。

#include<stdio.h> #include<windows.h>
#include<iostream>
using std::endl;
using std::cout;
/*****************
事實證明: 類的一般實例對象 只在所在函數有效,函數結束,這個類實例自動釋放資源。
***************/
#define DEBUG_FUNCTION_LINE() printf("#當前所在函數[%p] %s() 位於%d行\n",this,__FUNCTION__,__LINE__)


class CServer1{
public:
    int isExit;
public:
    CServer1(){
        this->isExit=0;
        DEBUG_FUNCTION_LINE();
    };
      CServer1(const CServer1&copy){
           DEBUG_FUNCTION_LINE();
           this->isExit=copy.isExit;
      };
~CServer1(){ this->isExit=-1; DEBUG_FUNCTION_LINE(); }; }; ////下面這個 函數 是否有缺陷??? CServer1 getPtrFunc (){ CServer1 *s=new CServer1(); s->isExit=15; return *s;//如果不用指針,局部變量會有錯誤的。Error 返回局部變量地址 是錯誤的。 //這句話 會 調用一個 析構函數 }; void func1(){ CServer1 foo; cout<<"開始 調用getPtrFunc返回值"<<endl; foo=getPtrFunc();//這樣賦值,是否 會存在內存泄漏???當然不會 cout<<"結束 調用getPtrFunc返回值"<<endl; std::cout<<" foo->isExist=" << foo.isExit << " [=15 是正常的]" <<endl;// //結束后,會執行 [拷貝后的對象]釋放 操作的! }; void func2(){ cout<<"開始 調用getPtrFunc返回值"<<endl; getPtrFunc();//這樣賦值,是否 會存在內存泄漏???當然不會 cout<<"結束 調用getPtrFunc返回值"<<endl; //結束后,會執行 釋放 操作的! }; CServer1 func31(){ CServer1 * s=new CServer1(); s->isExit=25; *s=getPtrFunc(); std::cout<<"In Func31: foo->isExist=" << s->isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return *s;//本句 導致new的對象 析構函數 被調用了。。。特無語啊。 //return CServer1(); }; CServer1 * func3(){ //此函數 第一個版本 //CServer1 *s; //s=&func31();//這一句 徹底失敗了。 應該是賦值 而不是 引用地址!! //cout<<"@@@ Func3.1完畢。"<<endl; //Sleep(1); //std::cout<<"In Func3: foo->isExist=" << s->isExit <<endl;//=15 是正常的 //此函數 第二個版本 正常,但是不是我想要的 /***** CServer1 s;//更改為 s 才正常了。 cout<<"開始 調用Func31。"<<endl; s=func31(); cout<<"結束 調用Func31。"<<endl; Sleep(1); std::cout<<"In Func3: foo->isExist=" << s.isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return NULL; *********/ //此函數 第三個版本,修改了返回值類型;此函數 如果不delete 會內存泄漏 CServer1 *ptr; ptr=new CServer1(); cout<<"開始 調用Func31。"<<endl; *ptr=func31(); cout<<"結束 調用Func31。"<<endl; Sleep(1); std::cout<<"In Func3: foo->isExist=" << (*ptr).isExit << " [=15 是正常的]" <<endl;//=15 是正常的 return ptr; }; int main(){ func1();//兩次 析構函數 cout<<"@@@ Func1 完畢。"<<endl<<endl; func2();//一次 析構函數 //這個函數證明了 很是OK ! cout<<"@@@ Func2 完畢。"<<endl<<endl; CServer1 * p=func3(); cout<<"@@@ Func3 完畢。"<<endl<<endl; delete p; cout<<"最后一個函數完成了,delete下 也就沒有內存泄漏了!!"<<endl; Sleep(20000); return 0; } /* #當前所在函數 CServer1::CServer1() 位於18行 開始 調用getPtrFunc返回值 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::~CServer1() 位於22行 結束 調用getPtrFunc返回值 foo->isExist=15 [=15 是正常的] #當前所在函數 CServer1::~CServer1() 位於22行 @@@ Func1 完畢。 開始 調用getPtrFunc返回值 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::~CServer1() 位於22行 結束 調用getPtrFunc返回值 @@@ Func2 完畢。 #當前所在函數 CServer1::CServer1() 位於18行 開始 調用Func31。 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::CServer1() 位於18行 #當前所在函數 CServer1::~CServer1() 位於22行 In Func31: foo->isExist=15 [=15 是正常的] #當前所在函數 CServer1::~CServer1() 位於22行 結束 調用Func31。 In Func3: foo->isExist=15 [=15 是正常的] @@@ Func3 完畢。 #當前所在函數 CServer1::~CServer1() 位於22行 最后一個函數完成了,delete下 也就沒有內存泄漏了!!

 

#當前所在函數[0x7fff57113b48] CServer1() 位於18行

開始 調用getPtrFunc返回值

#當前所在函數[0x7f90e0403a00] CServer1() 位於18行

#當前所在函數[0x7fff57113b38] ~CServer1() 位於22行

結束 調用getPtrFunc返回值

 foo->isExist=15 [=15 是正常的]

#當前所在函數[0x7fff57113b48] ~CServer1() 位於22行

@@@ Func1 完畢。

 

開始 調用getPtrFunc返回值

#當前所在函數[0x7f90e0403a10] CServer1() 位於18行

#當前所在函數[0x7fff57113b58] ~CServer1() 位於22行

結束 調用getPtrFunc返回值

@@@ Func2 完畢。

 

#當前所在函數[0x7f90e0403a20] CServer1() 位於18行

開始 調用Func31。

#當前所在函數[0x7f90e0403a30] CServer1() 位於18行

#當前所在函數[0x7f90e0403a40] CServer1() 位於18行

#當前所在函數[0x7fff57113ab8] ~CServer1() 位於22行

In Func31: foo->isExist=15 [=15 是正常的]

#當前所在函數[0x7fff57113b38] ~CServer1() 位於22行

結束 調用Func31。

In Func3: foo->isExist=15 [=15 是正常的]

@@@ Func3 完畢。

 

#當前所在函數[0x7f90e0403a20] ~CServer1() 位於22行

最后一個函數完成了,delete下 也就沒有內存泄漏了!!

 

*/

總結:

1.在getPtrFunc 函數中,雖然只有new,由於返回值 是 類實例  類型的,將指針 *p 返回,會在函數完成后自動銷毀(即調用了和new對應delete 對應的 析構函數)。

2. 返回值類型為類實例的函數 的時候,不能對函數 使用 & 。正如 func3 的第一個版本,其實已經訪問了釋放過內存的區域了。(isExist=-1了)是不安全的。

3.上面說明,函數返回值 其實在取值的時候 是賦值,而不是 傳遞 地址。將 內存 拷貝,復制,有點 memcpy 的感覺。char[] 數組 如果可以這樣賦值 多方便。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM