VC6下深入理解new[]和delete[](在多线程下new和delete的时候,必须选择上多线程库,不然可能造成进程崩溃)

  多少年了,一直处于C与C++混用的状态,申请空间一直用malloc,释放空间一直用free,为什么?因为他们好理解易操作,就如同输出一直用printf而不用<<,输入一直用scanf而不用>>。如果用new和delete,就会涉及到数组的问题,而我却一直没有好好理解过这种情况。今天突然有兴致深入分析下,于是写了下面一段代码:

复制代码
代码
#include <iostream>
using namespace std;

int g_i = 0;

class TestClass
{
public:
    int id;

    TestClass()
    {
        id = ++g_i;
        cout << id << " TestClass created." << endl;
    }

    ~TestClass()
    {
        cout << id << " TestClass deleted." << endl;
    }
};

int main(int argc, char* argv[])
{
    TestClass * pTestClass = new TestClass;
    delete pTestClass;

    return 0;
}
复制代码

  编译运行之后可以看到:

1 TestClass created.
1 TestClass deleted.

  反汇编之后可以看出,程序首先申请了4字节的空间,然后调用构造方法进行初始化,接着便把地址赋给了pTestClass,最后调用析构方法收尾并把空间释放掉:

复制代码
代码
push    4
call    operator_new

        ......

mov     ecx, [ebp+var_18]
call    TestClass__TestClass
mov     [ebp+var_24], eax

        ......

push    1
mov     ecx, [ebp+var_1C]
call    TestClass___scalar_deleting_destructor
复制代码

  再来看看申请对象数组的情况,将main函数中的代码修改为:

TestClass * pTestClass = new TestClass[4];
delete [] pTestClass;

  编译运行之后可以看到:

复制代码
1 TestClass created.
2 TestClass created.
3 TestClass created.
4 TestClass created.
4 TestClass deleted.
3 TestClass deleted.
2 TestClass deleted.
1 TestClass deleted.
复制代码

  反汇编之后可以看出,程序首先申请了20字节空间,然后将数组大小存放到前4个字节,调用构造方法将后面的4个对象指针初始化(4*4+4=20B),接下来才把空间指针赋给pTestClass。在清除空间的时候,程序根据存储在前4个字节中的长度,通过一个循环来从后往前调用每个对象的析构方法,最后才把空间释放掉:

复制代码
代码
push    14h
call    operator_new

        ......

push    offset TestClass___TestClass
push    offset loc_40128F
mov     eax, [ebp+var_18]
mov     dword ptr [eax], 4
push    4
push    4
mov     ecx, [ebp+var_18]
add     ecx, 4
push    ecx
call    vector constructor iterator

        ......

push    3
mov     ecx, [ebp+var_1C]
call    TestClass___vector_deleting_destructor
复制代码

  那么如果将main函数中的代码修改为申请一个对象的数组,情况又如何呢?

TestClass * pTestClass = new TestClass[1];
delete [] pTestClass;

  通过反汇编可以看出,即使是申请一个对象的指针数组,编译器的处理都是一样的,多申请4个字节的空间来保存数组大小。所以,只要在new操作时,使用了[],在delete时也必须使用[],否则,程序将把前面存贮数组大小的4个字节按照对象指针来处理,这样在调用析构方法的时候就会出错。

  那么如果是在一个文件中进行new操作,在另一个文件中delete的时候,如何判断使用delete还是delete []呢?一种方法是用一个变量来保存新申请对象的个数,在delete的时候进行判断,如果个数大于1,使用delete[],否则使用delete;另一种方法是,在申请对象的时候,一律用上[],这样在delete的时候也一律用上[]就没问题。


  最后我们来看看申请简单类型数组的情况,将main函数中代码改为:


int * pInt = new int[4];
delete [] pInt;

  反汇编后可以看到,由于是简单数据类型,不需要调用构造方法和析构方法,在申请空间时,没有多申请4个字节的空间来保存数组大小,所以,调用delete进行删除和调用delete []进行删除是完全一样的。

复制代码
push    10h
call    operator_new

        ......

push    edx
call    free_4062B0
复制代码

今天才发现,在多线程下new和delete的时候,必须选择上多线程库,不然可能造成进程崩溃,具体设置位置在工程设置“C/C++”选项卡的“Code Generation”下的“Use run-time library”中。

http://www.cnblogs.com/God4/articles/1887184.html#2320993

posted @ 2017-10-11 16:51  findumars  Views(1583)  Comments(0Edit  收藏  举报