代码之家  ›  专栏  ›  技术社区  ›  Matt Joiner

调用free()或delete而不是delete[]是否有危险?[复制品]

  •  6
  • Matt Joiner  · 技术社区  · 15 年前

    可能重复:
    ( POD )freeing memory : is delete[] equal to delete ?

    delete 取消分配数组中第一个元素以外的元素?

    char *s = new char[n];
    delete s;
    

    在上述情况下,将其视为 s 是连续分配的,不应该 删除 只有数组的一部分?

    对于更复杂的类型,会 删除 调用第一个对象以外的对象的析构函数?

    Object *p = new Object[n];
    delete p;
    

    怎样才能 delete[] 推导出 Object 超越了第一个,这是否意味着它必须知道分配的内存区域的大小?如果由于性能原因,内存区域被分配了一些挂起呢?例如,我们可以假设并非所有的分配器都提供单个字节的粒度。然后,任何特定的分配都可以通过一个或多个元素超过每个元素所需的大小。

    对于基本类型,例如 char , int ,两者之间有什么区别吗?

    int *p = new int[n];
    delete p;
    delete[] p;
    free p;
    

    除各电话通过 删除 -gt; free 解除机器交易?

    10 回复  |  直到 8 年前
        1
  •  15
  •   sharptooth    15 年前

    这是未定义的行为(很可能会立即损坏堆或使程序崩溃),您不应该这样做。只有与用于分配该内存的原语相对应的空闲内存。

    违反此规则可能会导致正确的功能巧合,但程序可以打破一旦任何东西被改变-编译器,运行时,编译器设置。你不应该依赖于这种正常的功能和期望。

    delete[] 使用编译器特定的服务数据来确定元素的数量。通常当 new[] 被调用时,号码存储在开头,调用方被赋予存储号码后面的地址。不管怎样 删除[ ] 依赖于正在分配的块 新[ ] ,不是别的。如果你配对除了 新[ ] 具有 删除[ ] 反之亦然,你会遇到不明确的行为。

        2
  •  10
  •   dirkgently    15 年前

    阅读常见问题解答: 16.3 Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()?

    在上述情况下,是否重要,因为s的所有元素都是连续分配的,不应该只删除数组的一部分?

    是的。

    delete[]如何推断第一个对象以外的对象数,这是否意味着它必须知道分配的内存区域的大小?

    编译器需要知道。见 FAQ 16.11

    因为编译器存储了这些信息。

    我的意思是编译器需要不同的 delete s生成适当的簿记代码。希望现在一切都清楚了。

        3
  •  5
  •   RED SOFT ADAIR    15 年前

    是的,这很危险!

    不要这样做!

    它将导致程序崩溃或更糟的行为!

    用于分配的对象 new 必须 使用 delete ;

    用于分配的对象 new [] 必须 使用 delete [] ;

    用于分配的对象 malloc() calloc() 必须 使用 free() ;

    还要注意,对于所有这些情况,再次删除/释放已删除/释放的指针是非法的。 free 也不能用空值调用。打电话 delete/delete[] 带空是合法的。

        4
  •  3
  •   AnT stands with Russia    15 年前

    是的,这是一个实际的危险。即使把实现细节放在一边,也要记住 operator new/operator delete operator new[]/operator delete[] 功能可以完全独立地替换。因此,明智的做法是 new/delete , new[]/delete[] , malloc/free 等等。作为不同的,完全独立的内存分配方法,它们完全没有共同点。

        5
  •  2
  •   user195317    15 年前

    RaymondChen(微软开发人员)有一篇深入的文章,介绍了scaler与vector删除之间的区别,并给出了一些不同的背景。见:

    http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

        6
  •  2
  •   Agnel Kurian    15 年前

    是否删除取消分配元素 在数组的第一个之外?

    不可以。无论您在哪个编译器上执行此操作,delete将只释放第一个元素。它在某些情况下可能会起作用,但这是附带的。

    在上述情况下,是否重要,因为S的所有元素都已分配 连续,不应该只删除数组的一部分?

    取决于内存标记为可用的方式。同样依赖于实施。

    对于更复杂的类型,delete会调用第一个类型之外的对象的析构函数吗?

    不,试试这个:

    #include <cstdio>
    
    class DelTest {
        static int next;
        int i;
    public:
        DelTest() : i(next++) { printf("Allocated %d\n", i); }
        ~DelTest(){ printf("Deleted %d\n", i); }
    };
    
    int DelTest::next = 0;
    
    int main(){
        DelTest *p = new DelTest[5];
        delete p;
        return 0;
    }
    

    如何删除[]来推断 第一个以外的物体,不会 这意味着它必须知道 分配的内存区域?

    是的,尺寸是放在某个地方的。存储它的位置取决于实现。例如,分配器可以将大小存储在分配地址之前的头中。

    如果记忆区域是 分配一些悬垂 绩效原因?例如一个 可以假定不是所有的分配器 将提供 单字节。那么有什么特别的吗 分配可能超过所需的 每个元素的整体大小 元素或更多。

    正是因为这个原因,返回的地址被设置为与单词边界对齐。使用sizeof操作符可以看到“悬垂”,并应用于堆栈上的对象。

    对于char、int之类的基元类型,在……之间有什么区别吗?

    对。malloc和new可能正在使用单独的内存块。即使事实并非如此,最好不要假定它们是相同的。

        7
  •  1
  •   MSalters    15 年前

    这是未定义的行为。因此,答案是:是的,可能有危险。而且不可能准确预测什么会引发问题。即使它只工作一次,它还会再次工作吗?它取决于类型吗?元素计数?

        8
  •  1
  •   big-z    15 年前

    对于char、int等基元类型,以下两种类型之间是否存在差异:

    我想你会有不明确的行为。所以你不应该指望稳定的行为。您应该始终使用new/delete、new[]/delete[]和malloc/free对。

        9
  •  0
  •   Paul Hsieh    15 年前

    虽然从某种逻辑上看,您可以混合使用new[]和free或delete而不是delete[],但这是基于编译器相当简单的假设,即它总是使用malloc()来实现新[]的内存分配。

    问题是,如果编译器有足够智能的优化器,它可能会看到没有与所创建对象的新[]对应的“delete[]”。因此,它可能会假定它可以从任何地方(包括堆栈)获取内存,以节省为新的[]调用实际malloc()的成本。然后,当您尝试调用free()或对其调用错误的delete类型时,它很可能会发生故障。

        10
  •  0
  •   Community CDub    7 年前

    步骤1请阅读: what-is-the-difference-between-new-delete-and-malloc-free

    您只看到开发人员方面看到的内容。
    您不考虑的是std lib如何进行内存管理。

    第一个区别是new和malloc从内存中的两个不同区域分配memroy(freestore和malloc堆中的新内存(不要关注基本上都是堆的名称,这些名称只是标准中的官方名称)。如果您从一个分配而从另一个取消分配,您将混淆用于管理内存的数据结构(没有保证它们将使用相同的结构进行内存管理)。

    当您分配这样的块时:

    int*   x= new int; // 0x32
    

    记忆可能是这样的:可能不会,因为我不费那么多心思就把它编好了。

    Memory   Value      Comment
    0x08     0x40       // Chunk Size  
    0x16     0x10000008 // Free list for Chunk size 40
    0x24     0x08       // Block Size
    0x32     ??         // Address returned by New.
    0x40     0x08       // Pointer back to head block.
    0x48     0x0x32     // Link to next item in a chain of somthing.
    

    重点是,在分配的块中有比分配给处理内存管理的int更多的信息。

    该标准并没有说明如何做到这一点(因为C/C++风格),他们不想依赖编译器/库制造商的能力来实现最有效的内存管理方法。

    考虑到这一点,您希望制造商能够区分阵列分配/解除分配与正常分配/解除分配,从而使其能够独立地对两种类型都有效。因此,您不能在内部进行混合和匹配,因为它们可能使用不同的数据结构。

    如果你实际上分析C和C++应用程序之间的内存分配差异,你会发现它们是非常不同的。因此,使用完全不同的内存管理技术来优化应用程序类型并不是不可停止的。这是在C++中更喜欢新的MalCube()的另一个原因,因为它可能会更有效(更重要的原因是,总是要减少复杂性(IMO))。