C++中關於new及動態內存分配的思考

如何實現一個malloc?

malloc_tutorial.pdf

————————————————————————————————————

    我們知道,使用malloc/calloc等分配內存的函數時,一定要檢查其返回值是否爲“空指針”(亦即是檢查分配內存的操作是否成功),這是良好的編程習慣,也是編寫可靠程序所必需的。但是,如果你簡單的把這一招應用到new上,那就不一定正確了。

    C++裏,如果new分配內存失敗,默認是拋出異常的如果你想檢查new是否成功,應該捕捉異常。

try{
        int* p = new int[SIZE];
        //其他代碼
    }catch( const bad_alloc& e ){
        return -1;
    }

當然,標準的C++亦提供了一個方法來抑制new拋出異常,而返回空指針:

int* p = new (std::nothrow) int; //這樣,如果new失敗了,就不會拋出異常,而是返回空指針
        if( p==0 )//如此這般,這個判斷就有意義了
            return -1//其他代碼

——————————————————————以上都是無用之談

new的語法格式:new 數據類型(初始化參數列表);

關於new後加()與不加()的區別:

  在用new建立一個類的對象時,若存在用戶定義的默認構造函數,則new T和new T()兩寫法效果相同,都會調用此默認構造函數;若未定義,new T會調用系統默認構造函數,new T()除了調用系統默認構造函數,還會給基本數據類型和指針類型的成員用0賦值,且該過程是遞歸的。即若該對象的某個成員對象未定義默認構造函數,那麼該成員對象的基本數據類型和指針類型的成員同樣會被以0賦值。

故用new的時候請加上()

運算符delete用來刪除由new建立的對象,釋放指針所指向的內存空間。

——————————————————————

關於new數組類型的對象:

語法格式: new 類型名 [數組長度];

delete[] 指針名;

如int* p = new int[10]();

delete[] p;

——————————————————————

多維數組:

語法格式: new 類型名T[第一維長度][第二維長度]...;

其中第1維長度是任何結果爲正整數的表達式,其餘必須是正整數的常量表達式(因爲是常量,故不能直接分配兩維都不固定的數組)。

若內存申請成功,返回指向新分配內存的首地址的指針,但不是T類型指針,而是指向T類型數組的指針,數組元素的個數爲除第一維外各維下標表達式的乘積。

如int (*p)[25][10];          //請把p抽出來看,p的類型爲 int* [25][10]

   p = new int[10][25][10];

則指針p即可以作爲指針用,也可以當一個三維數組名用。

再舉例如下:

int *p = new int[10];          //返回一個指向int的指針int*.

int (*p)[10] = new int[2][10];    //new了一個二維數組,返回一個指向int[10]這種一維數組的指針int(*)[10].

int (*p)[2][10] = new int[5][2][10]; //new了一個三維數組,返回一個指向二維數組int[2][10]這種類型的指針int (*)[2][10].

注意:new int[0][10]和new int[][10]都是無分配內存。

那麼如果第二維都不確定怎麼辦呢?

複製代碼
int **a = new int*[n];
    for(int i = 0; i < n; i++)
        a[i] = new int[n]();
//分配n*n的數組,還可以a[i] = new int[i]();有點java的味道...
  for(int i = 0; i < n; i++)
    delete[] a[i];
  delete[] a;
複製代碼

 

當char * a=new char[10]後,程序結束需要delete [] a請問爲什麼不需要寫delete [10] a ,即計算機是怎麼知道是數組大小的?
參考以下鏈接:
https://blog.csdn.net/hazir/article/details/21413833

How do compilers use “over-allocation” to remember the number of elements in an allocated array?

複製代碼
// Original code: Fred* p = new Fred[n];
char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
Fred* p = (Fred*) (tmp + WORDSIZE);
*(size_t*)tmp = n;
size_t i;
try {
  for (i = 0; i < n; ++i)
    new(p + i) Fred();           // Placement new
}
catch (...) {
  while (i-- != 0)
    (p + i)->~Fred();            // Explicit call to the destructor
  operator delete[] ((char*)p - WORDSIZE);
  throw;
}
複製代碼
// Original code: delete[] p;
size_t n = * (size_t*) ((char*)p - WORDSIZE);
while (n-- != 0)
  (p + n)->~Fred();
operator delete[] ((char*)p - WORDSIZE);

How do compilers use an “associative array” to remember the number of elements in an allocated array?

複製代碼
// Original code: Fred* p = new Fred[n];
Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
size_t i;
try {
  for (i = 0; i < n; ++i)
    new(p + i) Fred();           // Placement new
}
catch (...) {
  while (i-- != 0)
    (p + i)->~Fred();            // Explicit call to the destructor
  operator delete[] (p);
  throw;
}
arrayLengthAssociation.insert(p, n);
複製代碼
// Original code: delete[] p;
size_t n = arrayLengthAssociation.lookup(p);
while (n-- != 0)
  (p + n)->~Fred();
operator delete[] (p);

參考鏈接:https://isocpp.org/wiki/faq/compiler-dependencies#num-elems-in-new-array-overalloc

malloc/free與new/delete的策略類似,new/delete是malloc/free的上層

https://stackoverflow.com/questions/197675/how-does-delete-know-the-size-of-the-operand-array

 

====================================================================

 

隱式空閒鏈表(任何操作的開銷都與堆中已分配塊和未分配塊的總數呈線性關係)

帶邊界標記的合併(塊分配與堆塊的總數呈線性關係,合併空閒塊常數時間)

顯式空閒鏈表(分配時間從塊總數減少爲空閒塊數量的線性時間,釋放時間取決於空閒鏈表塊的排序策略,LIFO則常數時間釋放,按地址順序排序則線性時間釋放,如果採用了邊界標記,合併時間常數)

分離的空閒鏈表:簡單分離存儲 / 分離適配 / 夥伴系統

諸神對凡人心生豔羨,厭倦天堂。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章