zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    C#里的async和await的使用
    解决 .NET CORE3.0 MVC视图层不即时编译
    【转】CSS实现自适应分隔线的N种方法
    iscrolljs 看API 回顾以前开发中失误
    自由了-和过去说再见
    js 性能基准测试工具-告别可能、也许、大概这样更快更省
    dom事件不求甚解,色解事件捕获和冒泡
    百度mobile UI组件GMU demo学习1-结构和初始化
    自己收集原生js-2014-2-23
    如何在电脑上测试手机网站(补充)和phonegap
  • 原文地址:https://www.cnblogs.com/findumars/p/7651467.html
Copyright © 2011-2022 走看看