不用看了,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©){
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©){
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[] 數組 如果可以這樣賦值 多方便。