第十六章 內存管理(1)====高質量程序設計指南C/C++編程

內存分配方式:

                 1.從靜態存儲區分配,內存在程序編譯的時候就已經分配好了(即已經編址),這些內存在程序的整個運行期間都存在,如全局變量,static變量等。

                 2.在堆棧上分配,在函數執行期間,函數內部變量(包括形參)的存儲單元都創建在堆棧上,函數結束這些存儲單元自動釋放,堆棧清退。堆棧內存分配運算內置於處理器的指令集中,效率很高,並且一般不存在失敗的危險,但是分配的內存容量有限,可能出現堆棧溢出。

                  3.從堆(heap)或自由存儲空間上分配,即動態內存分配,程序在運行期間,用malloc()或者new申請任意數量的內存,程序員自己掌握釋放內存的恰當時機(使用free()或delete),動態內存的生存期由程序員決定,使用靈活、


常見的內存錯誤:

  1.內存尚未分配成功,卻使用了。   檢查指針是否爲空

                  2.內存分配成功,但是尚未初始化就使用它    任何的分配需要初始化

                  3.內存分配成功已經初始化,但是訪問越過了內存的邊界。 如數據的越界訪問

                   4.忘記釋放內存或者只是釋放了一部分的內存,導致內存泄露。 malloc() free()   new delete 使用必須配對

                   5.釋放了內存卻還在使用。  注意將已經釋放的內存設置爲NULL,防止產生野指針。 多次釋放同一塊內存出現錯誤。 double free

    

幾點規則:

              1.用malloc()或者new申請內存之後,應該立即檢查指針值是否爲NULL或者進行異常處理,以防止使用值爲NULL的指針。

              2.不要忘記初始化指針,數組和動態內存,防止將未初始化的內存作爲右值使用。

               3.避免數組下標訪問越界。

              4.動態內存的分配和釋放必須配對,防止內存泄露。

              5.釋放內存後應該立即把指針設置成NULL,防止野指針。


指針參數如何傳遞內存:
               1.指針作爲參數進行內存的分配,傳遞指針的指針,或者傳遞指針的引用。因爲實參是拷貝一份傳遞給形參。

                

void getmemory(char** p,int num)
{
    *p=(char*)malloc(sizeof(char)*num);
}

void getmemory(char*& p,int num)
{
    p=new char;
}

              2.用函數返回值傳遞來申請內存

char* getmemory(int num)
{
    char* p=NULL;
    p=(char*)malloc(num*sizeof(char));
    return p;
}
   

                3.注意不可以返回局部變量的地址

char* getmemory(int num)

{
    char* p="hello world";
    return p;
}
char* getmemory()
{
    char p[]="hello world";
    return p;
}
第一種 返回常量存儲區的地址OK 第二種錯誤!!


內存釋放:

         

#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

int main()
{
    int* p=new int(5);
    if(p==NULL) throw 1;
    cout<<p<<endl;
    delete p;
    cout<<p<<endl;
    return 0;
}

指針被釋放後其指向的地址內人不變,(不等於NULL),但是該地址對應的內存是垃圾------>p成了一個野指針。 所以必須進行設置成NULL


經典:指針消亡了,並不代表它所指的內存會被自動釋放  AND  內存被釋放了,並不表示指針會消亡或者成了NULL。

野指針:

           1.未初始化指針變量,任何指針在初始化時不會自動成爲NULL指針,它會亂指一氣,所以指針變量創建的同時應該初始化,或者設置成NULL。

           2,.指針p被釋放後,未設置爲NULL。

           3.指針變量超越了變量的作用範圍。

class A{
public:
     void func(void){cout<<"A::func"<<endl;}
     ~A(){cout<<"~A()"<<endl;}
};
int main()
{
    A* p=NULL;
    {
       A a;
       p=&a;//注意a的生命期
    }
    p->func();//p是野指針
    return 0;
}
上述代碼: 根本原因是a雖然退棧,但是僅僅是調用了析構函數,並沒有清除a的內存(a的內存仍然在函數堆棧上),所以結果沒有錯。


MALLOC FREE AND NEW DELETE

maloc,free爲C語言的庫函數,而不是運算符。 new delete是運算符而不是庫函數

用malloc,free函數進行對象的動態內存管理,不能調用構造函數和析構函數。必須程序員自己寫函數來完成初始化和清除的工作。

new.delete會自動的調用構造和析構函數來進行調用。

某些情況下,malloc/free效率更高。用戶可以自定義類重載 new/delete實現個性的內存分配和釋放策略。

注意:如果使用free()來釋放new創建的對象,那麼該對象可能會無法執行析構函數而導致程序出錯, C++並不保證new的底層會用malloc(),而且在一些實現中,malloc和new使用不同的堆,同樣,用delete釋放malloc申請的動態內存,理論是程序不會出錯,但是該程序的可讀性會很差。

p==NULL free多次都沒事,但是p!=NULL,多次釋放會出現錯誤




發佈了37 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章