代码之家  ›  专栏  ›  技术社区  ›  Satbir

delete[]是否等于delete?

  •  43
  • Satbir  · 技术社区  · 15 年前
    IP_ADAPTER_INFO *ptr=new IP_ADAPTER_INFO[100];
    

    如果我免费使用

    delete ptr;
    

    ; delete ptr;
    0041351D  mov         eax,dword ptr [ptr] 
    00413520  mov         dword ptr [ebp-0ECh],eax 
    00413526  mov         ecx,dword ptr [ebp-0ECh] 
    0041352C  push        ecx  
    0041352D  call        operator delete (4111DBh) 
    00413532  add         esp,4 
    
    ; delete []ptr;
    00413535  mov         eax,dword ptr [ptr] 
    00413538  mov         dword ptr [ebp-0E0h],eax 
    0041353E  mov         ecx,dword ptr [ebp-0E0h] 
    00413544  push        ecx  
    00413545  call        operator delete[] (4111E5h) 
    0041354A  add         esp,4 
    
    6 回复  |  直到 4 年前
        1
  •  154
  •   thecoshman    8 年前

    这是否会导致内存泄漏、擦除硬盘、让你怀孕、让讨厌的鼻魔在你的公寓里追你,或者让一切正常工作而没有明显的问题,这些都是未知的。一个编译器可能是这样,另一个编译器可能会改变,新的编译器版本可能会改变,每次新的编译,月亮的相位,你的心情,或者取决于最后一个阳光明媚的下午通过处理器的中微子的数量。也可能不是。

    所有这些,以及无数其他可能性都被放在一个术语中: 未定义的行为 :

        2
  •  14
  •   jichi    11 年前

    这只是某些操作系统和编译器上一些“未定义”行为的示例。希望它能对人们调试代码有所帮助。

    测试1

    #include <iostream>
    using namespace std;
    int main()
    {
      int *p = new int[5];
      cout << "pass" << endl;
      delete p;
      return 0;
    }
    

    测试2

    #include <iostream>
    using namespace std;
    int main()
    {
      int *p = new int;
      cout << "pass" << endl;
      delete[] p;
      return 0;
    }
    

    测试3

    #include <iostream>
    using namespace std;
    struct C {
      C() { cout << "construct" << endl; }
      ~C() { cout << "destroy" << endl; }
    };
    
    int main()
    {
      C *p = new C[5];
      cout << "pass" << endl;
      delete p;
      return 0;
    }
    

    #include <iostream>
    using namespace std;
    struct C {
      C() { cout << "construct" << endl; }
      ~C() { cout << "destroy" << endl; }
    };
    
    int main()
    {
      C *p = new C;
      cout << "pass" << endl;
      delete[] p;
      return 0;
    }
    
    • Windows 7 x86,msvc 2010。使用默认选项编译,即启用异常处理程序。

    测试1

    pass
    

    测试2

    测试3

    construct
    construct
    construct
    construct
    construct
    pass
    destroy
    # Then, pop up crash msg
    

    construct
    pass
    destroy
    destroy
    destroy
    destroy
    destroy
    destroy
    destroy
    ... # It never stop until CTRL+C
    
    • Mac OS X 10.8.5、llvm gcc 4.2或gcc-4.8生成相同的输出

    测试1

    通过
    

    测试2

    通过
    

    construct
    construct
    construct
    construct
    construct
    pass
    destroy
    a.out(71111) malloc: *** error for object 0x7f99c94000e8: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
    zsh: abort      ./a.out
    

    测试4

    construct
    pass
    a.out(71035) malloc: *** error for object 0x7f83c14000d8: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
    zsh: abort      ./a.out
    

    测试1

    通过
    

    通过
    

    测试3

    construct
    construct
    construct
    construct
    construct
    *** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x0000000001f10018 ***
    ======= Backtrace: =========
    /lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fe81d878b96]
    ./a.out[0x400a5b]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fe81d81b76d]
    ./a.out[0x4008d9]
    ======= Memory map: ========
    ....
    zsh: abort (core dumped)  ./a.out
    

    测试4

    construct
    destroy
    destroy
    destroy
    destroy
    destroy
    destroy
    destroy
    destroy
    ...
    destroy
    destroy
    *** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000016f6008 ***
    ======= Backtrace: =========
    /lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fa9001fab96]
    ./a.out[0x400a18]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fa90019d76d]
    ./a.out[0x4008d9]
    ======= Memory map: ========
    ...
    zsh: abort (core dumped)  ./a.out
    
        3
  •  7
  •   Community CDub    8 年前

    它通常不会泄漏,因为在POD的情况下,析构函数是微不足道的,所以不需要调用它们 delete 只需释放阵列占用的内存。内存释放只需要一个指针值,因此它将返回到堆中。数组容纳一个连续的内存块,因此释放可以成功,就像它是单个元素的释放一样。

    但不要依赖于此,因为这是未定义的行为。也许它工作正常,也许发生了一些可怕的事情,在这个编译器上工作,在另一个编译器上不工作,很多人感谢你植入了一个错误。

    this answer 详情请参阅。

        4
  •  5
  •   FranckSpike    13 年前

    删除 : 仅用于元素的析构函数 指向(如果需要),

    删除[] 每个元素的析构函数 在其阵列中(如果需要), 然后释放内存块

        5
  •  5
  •   Andrejs Cainikovs    5 年前

    未定义 并且会因编译器而异。例如,MSVC编译器将生成与GCC不同的代码。

    如果A指向通过新T[n]分配的数组,则必须通过delete[]A将其删除。delete和delete[]之间的区别很简单——前者破坏标量对象,后者破坏数组。

        6
  •  -4
  •   Sergey Podobry    15 年前

    对于数组 豆荚 会的 不漏 (拥有最多的编译器)。例如 产生 完全相同的 删除 删除[] 豆荚 .

    就我个人而言,我认为C/C++可以不使用操作符delete[]。编译器知道对象大小,分配的内存大小在运行时是已知的,因此很容易知道是否是指针数组,并以正确的方式处理内存。

    好的,伙计们。你能在你的编译器上测试一下它是否泄漏吗?

    , 新[] , 删除 删除[] . 每个 删除 . 看起来完美而完整。让我们看看你打电话时发生了什么 删除[] ?

    1. call vector destructor for an object
    2. actual free memory
    

    析构函数的作用是什么 豆荚 ? 没有什么! 那么,打电话 删除 豆荚 不会泄漏!即使它违反了标准。即使不推荐。

    编辑2:

    operator delete[]:
    78583BC3  mov         edi,edi 
    78583BC5  push        ebp  
    78583BC6  mov         ebp,esp 
    78583BC8  pop         ebp  
    78583BC9  jmp         operator delete (78583BA3h)