编译器如何知道使用哪个运算符或函数分配了哪个内存?

时间:2014-07-23 11:48:41

标签: c++ memory-management malloc new-operator

假设我为两个数组分配了内存,一个使用new运算符,另一个使用malloc函数。据我所知,两个内存都分配在堆段中,那么我的问题是编译器将如何知道哪个内存是使用哪个运算符或函数分配的?或者这背后是否还有其他概念。

8 个答案:

答案 0 :(得分:1)

编译器不必知道指针后面的内存是如何分配的,这是程序员的责任。您应该始终使用匹配的allocate-deallocate函数/运算符。例如,new new可能会过载。在这种情况下,当你使用new分配对象,并使用free()释放它时,你会遇到麻烦,因为free()不知道你有什么样的簿记。这里简化了这种情况的一个例子:

#include <iostream>
#include <stdlib.h>


struct MyClass
{
    // Really dumb allocator.
    static void* operator new(size_t s)
    {
        std::cout << "Allocating MyClass " << s << " bytes.\n";
        void* res = Pool + N * sizeof(MyClass);
        ++N;
        return res;
    }

    // matching operator delete not implemented on purpose.

    static char Pool[]; // take memory from this statically allocated array.
    static unsigned N; // keep track of allocated objects.
};

char MyClass::Pool[10*sizeof(MyClass)];
unsigned MyClass::N = 0;

int main(int argc, char** argv)
{
    MyClass* p = new MyClass();

    if (argc == 1)
    {
        std::cout << "Trying to delete\n";
        delete p; // boom - non-matching deallocator used.
    }
    else
    {
        std::cout << "Trying to free\n";
        free(p); // also boom - non-matching deallocator used.
    }
}

如果你混合并匹配分配器和解除分配器,你将遇到类似的问题。

答案 1 :(得分:0)

在内部,两种分配机制可能会或可能不会最终使用相同的机制,但配对newfreemallocdelete会在概念上混合不同的事物并导致未定义的行为。

答案 2 :(得分:0)

deletemalloc free不得使用new。虽然对于基本数据类型,您可能会在大多数编译器上使用它,但它仍然是错误的。它不能保证工作。 mallocnew可以处理不同的堆,而不是同一个堆。此外,delete将调用对象的析构函数,而free则不会。

编译器不必跟踪malloc或new分配的内存块。它们可能是调试帮助,也可能不是。不要依赖它。

答案 3 :(得分:0)

  • new / delete是分配内存和从堆中释放内存的C ++方法

,而

  • malloc / free / family是从堆中分配和释放内存的C方式

我不知道为什么你希望编译器知道谁分配了堆内存但是 如果你想跟踪有什么方法。

这样做的一种方法是new将通过调用构造函数来初始化已分配的内存,您可以监视此构造函数以了解将内存分配给堆的人。

此致 yanivx

答案 4 :(得分:0)

它不知道。它只调用一个返回指针的函数,而指针不包含它们如何成为的信息或它们指向的内存类型。它只是传递指针而不再关心它。

但是,用于释放内存的功能(例如free / delete)可能取决于存储在malloc / new隐藏的某处的信息。因此,如果您按malloc分配内存并尝试使用delete(或newfree)取消分配内存,则可能无效(除了构造函数的明显问题) /析构函数)。

可能无法正常工作在这种情况下,未定义会发生什么。这对于cmpiler开发人员和性能来说是一个巨大的好处,因为他们根本不需要关心。另一方面,努力推迟到必须跟踪某些内存分配方式的开发人员。最简单的方法是使用两种方法中的一种。

答案 5 :(得分:0)

  

据我所知,两个内存都是在堆段中分配的,那么我的问题是编译器将如何知道哪个内存是使用哪个运算符或函数分配的?

你称之为&#34;堆段&#34;是什么?

就C和C ++标准而言,没有这样的东西。 &#34;堆&#34; &#34; stack&#34;是特定于实现的概念。它们是非常广泛使用的概念,但它们都没有标准要求a&#34; heap&#34;或者&#34;堆栈&#34;。

实现(不是编译器!)如何知道分配的位置取决于实现。您最好的选择,也是唯一安全的选择,就是遵循标准所要做的事情:

  • 如果使用new[]分配内存,则必须使用delete[]解除分配(或保留未删除的内容)。
    任何其他释放都是未定义的行为。

  • 如果使用new分配内存,则必须使用delete解除分配(或保留未删除的内容)。
    任何其他释放都是未定义的行为。

  • 如果您使用malloc或其亲属分配内存,则必须使用free取消分配内存(或保留未删除的内容)。
    任何其他释放都是未定义的行为。


不释放分配的内存有时可能是一个严重的问题。如果你不断分配大块内存并且永远不会释放一个内存,你就会遇到问题。其他时候,它根本不是问题。在程序启动和oops分配一块内存时,你没有释放它通常不是问题,因为当程序终止时释放分配的内存。由您来决定这些内存泄漏是否确实存在问题。

避免这些大问题的最简单方法是让程序在程序退出之前正确释放已分配内存的每个字节。

请注意:这样做并不能保证您不会遇到内存问题。仅仅因为你的程序最终应该释放在程序执行过程中分配的多个TB的每一个,并不一定意味着程序在记忆方面是好的。

答案 6 :(得分:0)

free()和delete函数之间存在类似的差异。使用free(),不会调用对象的析构函数。使用delete,将调用析构函数并正确清理对象。

答案 7 :(得分:0)

当你使用new []时,分别删除[]这些调用构造函数和解构函数。这意味着你的类实例被初始化并自动取消初始化,但malloc和free不分别调用构造函数和解构函数。

所以当你为一个用new分配的对象调用free()时,它的析构函数不会被调用,你可能会得到内存泄漏。因此必须使用delete [],因为内存是用new []分配的。否则这可能导致undefined行为,最有可能导致崩溃。