1. 程式人生 > >C++懸掛指標: new與delete的一些理解

C++懸掛指標: new與delete的一些理解

這是我的第一篇技術部落格,淺顯簡短。

不多說,直接上程式碼:

#include <iostream>
using namespace std;
class test{
	private:
	int myprivateNum;
	public:
	test():myprivateNum(0){
		cout<<"the test begin with "<<myprivateNum<<endl;
	}
	test(int i):myprivateNum(i){
		cout<<"the test begin with "<<myprivateNum<<endl;
	}
	~test(){
		cout<<"the test is done!\n";
	}
	void printsomething()
	{
		cout << "something\n";
	}
	int getMyNum(){
		return myprivateNum;
	}
	void setMyNum(int num){
		myprivateNum = num;
	}
};
int main(int argc, char *argv[])
{
	test* myTest         = (test*)new test(3);    //可以顯示呼叫含參建構函式,注意區別 
	test* myTestArray    = (test*)new test[10];   //動態生成陣列時,會呼叫預設建構函式(無參),不能自己顯示呼叫想要的含參建構函式哦~ 
	(*myTestArray).printsomething();
	(myTestArray+1)->printsomething();            //驗證返回陣列的頭指標      
	test* myTestNull     = NULL;
	myTestNull->printsomething(); 		      //不會出現錯誤,因為是靜態繫結(考慮到快取效能,編譯期已經生成),所以根本沒有用這個指標哦~ 函式會預設把呼叫它的指標當作引數傳入 
	//myTestNull->getMyNum();	              //會出現指標為空的錯誤
	
	
	 
	cout<<myTest->getMyNum()<<endl;             //正常輸出 
	/*
	//delete後如果未清空指標,那麼這段記憶體在未被重新使用之前也許可以正常訪問;但是這段記憶體同樣是可分配使用的,
	//這就導致該指標訪問相應記憶體時不知道這段記憶體存了啥二進位制資料(未定義的行為); 
	//所以稱為懸掛指標,能著地,但底下已被架空,說不定你想要著的自己家的沙發,結果落到了別人家廁所坑。 
	*/
	delete myTest;
	cout<<myTest->getMyNum()<<endl;  //隨機資料 
	myTest->setMyNum(25);            //為什麼依舊可以訪問 
	//myTest               = NULL;   //將指標設為空後,就不能亂呼叫這段記憶體啦,所以一般指標delete後沒有特殊用處的話會繼續設為NULL 
	cout<<myTest->getMyNum()<<endl;  //為什麼會正常輸出 
	delete myTest;
	cout<<myTest->getMyNum()<<endl;  //為什麼會正常輸出
	return 0;
}


問題總結:

1)C++ new會返回一個指向相應例項的指標,並自動呼叫該例項的建構函式,如果是動態請求一個數組,則返回陣列的頭指標,並自動為陣列每個例項呼叫預設建構函式。

2)C++空的類指標依舊可以呼叫類的函式,這是因為++類非virtual函式靜態繫結的原因,在編譯期就與該類繫結,之後所有該類的例項都可以共用啦,不用重新繫結快取了,所以呼叫函式該根本用不到例項指標(this),非空的話也不會出現錯誤啦。

3)C++ delete指標後,只會把記憶體標記為可使用,記憶體在未被重新使用之前也許還能正常訪問呢,delete而且不負責把指標設定為空,所以指標依舊可以訪問到那段記憶體。

4)這就導致該指標訪問相應記憶體時其實無法確定這段記憶體存了啥二進位制資料(未定義的行為),所以稱為懸掛指標,能著地,但底下已被架空,說不定你想要著的自己家的沙發,結果落到了別人家廁所坑。

5)一般指標delete後沒有特殊用處的話會繼續清空指標,即設為NULL,這樣就不會亂讀以及干擾那段可以被別人使用的記憶體啦,乾淨了舒服。