'scalar deleting destructor' 和 'vector deleting destructor'的區別


在用到delete的時候,我們往往會針對類對象與類對象數組做不同刪除,在這背后編譯器是如何做的?

#include<iostream>
using namespace std;

class A{
    int a;
public:    ~A(){
        printf("delete A\n");
    }
};


int main(){
    A *pa = new A ;
    A *pas = new A[10] ;
    //delete  []pas;                //詳細流程
    //delete []pa;                //會發生什么
    //delete pas;                    //會怎么樣

    getchar();
}

 

從匯編的角度來看:在C++的delete與delete[]對應'scalar deleting destructor'或 'vector deleting destructor'

void scalar_deleting_destructor(A* pa)
{
pa->~A();
A::operator delete(pa);
}
void vector_deleting_destructor(A* pa, size_t count)
{
for (size_t i = 0; i < count; ++i)
pa[i].~A();
A::operator delete[](pa);
}
//delete  []pas;                //會調用10次析構函數在free
//delete []pa;                //超出范圍的內存會被收回,VS: 編譯正確,運行出錯

//delete pas; //會怎么樣,VS: 編譯通過,運行報錯 VC:編譯通過,可以運行,但只調用一次析構函數


一下用於VS的解釋:
參考

好,現在討論在VS下用delete刪除一個對象數組指針時報錯的問題。

根據報錯,我們會跟到一個dbgdel.cpp文件中,

  /* verify block type */
  _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

 

 

先看一個數據結構定義:就是DEBUG下系統對內存進行管理的一個數據結構:

 

_CrtMemBlockHeader * pHead;

typedef struct _CrtMemBlockHeader
{
        struct _CrtMemBlockHeader * pBlockHeaderNext;
        struct _CrtMemBlockHeader * pBlockHeaderPrev;
        char *                      szFileName;
        int                         nLine;
 #ifdef _WIN64
        /* These items are reversed on Win64 to eliminate gaps in the struct
         * and ensure that sizeof(struct)%16 == 0, so 16-byte alignment is
         * maintained in the debug heap.
         */
        int                         nBlockUse;
        size_t                      nDataSize;
#else  /* _WIN64 */
        size_t                      nDataSize;
        int                         nBlockUse;
#endif  /* _WIN64 */
         long                        lRequest;
        unsigned char               gap[nNoMansLandSize];
        /* followed by:
         *  unsigned char           data[nDataSize];
         *  unsigned char           anotherGap[nNoMansLandSize];
         */
} _CrtMemBlockHeader;

可以看出來,這是一個雙向的鏈表,(每一個結構中都包含一個pre和next指針)。 還包含如下信息: 申請空間的文件名、所在行數、用戶申請的數據大小, 內存塊的類型,用於內存管理信息的額外空間。

現在來看出錯的斷言:

 

 /* verify block type */
 _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

我們傳進去的參數, pHead->nBlockUse的值為147 看看是如何判斷一個內存塊的是否是合法的。

#define _BLOCK_TYPE_IS_VALID(use) (_BLOCK_TYPE(use) == _CLIENT_BLOCK || \
                                              (use) == _NORMAL_BLOCK || \
                                   _BLOCK_TYPE(use) == _CRT_BLOCK    || \
                                              (use) == _IGNORE_BLOCK)

 

而BLOCK_TYPE(use)又是怎么的宏定義呢:

 

#define _BLOCK_TYPE(block)  (block & 0xFFFF)

 

我們的參數穿進去之后,還是147啊。 而
CLIENT_BLOCK    4
NORMAL_BLOCK    1
CRT_BLOCK       2
IGNORE_BLOCK    3

 

沒一個條件能成立,所以斷言不成立,系統就會彈出那么大的錯誤提示框。
 
但是為什么我們穿進去的參數會是147呢?
參考:http://m.oschina.net/blog/55763
 


免責聲明!

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



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