C++的動態記憶體管理是通過new和delete兩個操作來完成的,即用new來申請空間,用delete來釋放空間,在使用new和delete時,注意以下原則,

1.new與delete需一一對應
用new操作申請空間,如果申請成功,必須在以后的某個時刻用delete釋放該空間,既不能忘記釋放,也不能多次釋放,前者會引起記憶體泄露,后者會引起運行時錯誤,如下面的程式,
#include <iostream>
usingnamespacestd;
intmain()
{
int*p;
p=newint(3);
if(p)
{
deletep;
}
deletep;
return0;
}
以上程式對指標p所指向的空間進行兩次釋放,這種記憶體錯誤對C++程式危害極大,也是很多人對C++忘而卻步的原因,多次釋放同一塊記憶體空間,并不一定立即引起程式運行錯誤,也不一定會導致程式運行的崩潰,這跟具體的編譯器實作有關,但是,多次釋放同一塊記憶體空間絕對是一個編程錯誤,這個編程錯誤可能會在其后的某個時刻導致其他的邏輯錯誤的發生,從而給程式的除錯和糾錯帶來困難,考察如下程式,
#include <iostream>
usingnamespacestd;
intmain()
{
int*p,*q,*one;
one=newint;
if(one)
{
cout<<one<<endl;
}
deleteone;
p=newint(3);
if(p)
{
cout<<p<<endl;
}
deleteone;//假設這句陳述句是程式員不小心加上的
q=newint(5);
if(q)
{
cout<<q<<endl;
}
cout<<(*p)+(*q)<<endl;
deletep;
deleteq;
}
程式通過編譯,運行結果如下:
003289A0
003289A0
003289A0
10
程式運行程序中會產生中斷,從程式的輸出可以看出,在將指標one所指向的空間釋放后,為指標p申請的空間就是原來one所指向的空間,由于不小心在為p分配空間之后再次使用了delete one,導致q申請到的空間就是原來p所申請的空間,這樣賦給*q的值就改寫了原來p所指向的單元的值,導致最后輸出結果為10,由此可知,多次釋放同一塊記憶體空間,即使不導致程式運行中斷,也會破壞環境,使指標與所對應的空間的隸屬關系出現混亂,從而導致邏輯錯誤,在大型程式設計中,這種邏輯錯誤的查找會變得十分費時費力,
**注意:**當指標p的值為NULL時,多次使用delete p并不會帶來麻煩,因為釋放空指標的空間實際上不會導致任何操作,所以,將“不用”的指標設定為NULL是一個好的編程習慣,
2.new[]與delete[]需一一對應
在申請物件陣列時,需要使用new[]運算子,與之對應,釋放物件陣列時,需要使用delete[]運算子,這一點與C語言有所區別,C中無論申請單個還是多個物件,均使用malloc()/free()函式,首先看一下delete與delete[]運算子的區別,
classTest
{
public:
Test() { cout<<"ctor"<<endl; }
~Test() { cout << "dtor"<< endl; }
};
//segment1
Test* pArray1 = newTest[3];
deletepArray1;
//segment2
Test* pArray2 = newTest[3];
delete[] pArray2;
其中代碼片段segment1運行結果如下:
ctor
ctor
ctor
dtor
segment2運行結果如下:
ctor
ctor
ctor
dtor
dtor
dtor
可以看出,delete與delete[]區別在于釋放物件陣列時,delete只呼叫了一次解構式,delete[]呼叫了三次解構式,完成了物件陣列的釋放,實際上,在使用new和new[]申請記憶體空間時,會申請一段額外的記憶體來保存用戶申請的記憶體空間大小,元素個數等資訊,當使用delete[]釋放記憶體空間時,會逐個呼叫物件的解構式并完成最終的記憶體空間的釋放,使用delete釋放物件陣列時,則只會呼叫單個物件的解構式,造成記憶體泄漏,符號[]告訴編譯器,在delete一塊記憶體時,先去獲取記憶體保存的元素個數,然后一一清理,所以使用delete釋放new[]申請的記憶體空間和使用delete[]釋放new申請的記憶體空間都錯誤的做法,
具體使用時,需要注意以下兩點:
(1)對于內置資料型別,因為沒有構造和解構式,所以使用delete和delete[]的效果是一樣的,比如:
int* pDArr=newint[3];
//processing code
deletepDArr; //等同于delete[] pDArr
對于內置資料型別,雖然可以使用delete完成物件陣列記憶體空間的釋放,但是為了保證代碼的可讀性,建議使用delete[]來完成,所以,new[]與delete[]使用時應一一對應,
(2)對于經常使用typedef的程式員來說,很容易new[]與delete的混用,例如有如下操作:
typedefintHeight[NUM];
int* pHeight=newHeight;
這個情況應該使用delete還是delete[]呢?答案如下:
deletepHeight; //wrong,但容易錯誤地使用delete
delete[] pHeight; //right
為了避免出現上面的錯誤,建議不要對陣列使用typedef,或者采用STL中的vector代替陣列,
3.建構式中的new/new[]與解構式的中delete/delete[]需一一對應
當類的成員中有指標變數時,在建構式中用new申請空間并且在解構式中用delete釋放空間是一種“標準的”、安全的做法,例如下面的程式,
#include <iostream>
usingnamespacestd;
classStudent
{
char* name;
public:
Student()
{
cout<<"Default constructor"<<endl;
}
Student(char*);
~Student();
};
Student::Student(char*s)
{
//Student();//此句運行時報錯,建構式不能呼叫其他建構式
cout<<"In constructor,allocating space"<<endl;
name=newchar[strlen(s)+1];
strcpy(name,s);
cout<<"name:"<<name<<endl;
}
Student::~Student()
{
cout<<"In destructor, free space"<<endl;
deletename;
}
intmain()
{
Student s1("張三");
}
程式運行輸出:
In constructor,allocating space
name:張三
In destructor, free space
由于任何一個物件,其建構式只呼叫一次,其解構式也只呼叫一次,這樣就能保證運行時new和delete操作是一一對應的,也就保證了記憶體管理的安全性,
在C++中,一個建構式不能呼叫本類的另一個建構式,其原因就是為了防止建構式的相互呼叫打破了記憶體申請與釋放之間的這種對應關系,
以上就是C++ 使用new與delete需注意的原則的詳細內容,有什么問題歡迎大家評論區留言,

最后,如果你也想成為程式員,想要快速掌握編程,趕緊加入學習企鵝圈子!
里面有資深專業軟體開發工程師,在線解答你的所有疑惑~編程語言入門“so easy”
編程學習書籍:

編程學習視頻:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/235856.html
標籤:C++
