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則常數時間釋放,按地址順序排序則線性時間釋放,如果采用了邊界標記,合並時間常數)

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM