【问题标题】:What if, memory allocated using malloc is deleted using delete rather than free如果使用 malloc 分配的内存使用 delete 而不是 free 删除怎么办?
【发布时间】:2013-12-10 07:12:33
【问题描述】:

我遇到了一个我无法解决的问题。

我的问题是,如果我使用malloc 分配内存,然后使用delete 删除内存块? 一般的经验法则是

如果我们使用 ma​​lloc 分配内存,则应该使用 free 将其删除。

如果我们使用 new 分配内存,则应该使用 delete 将其删除。

现在,为了检查如果我们反过来会发生什么,我写了一个小代码。

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

class A
{
  int p=10;
public:
  int lol() {
    return p;
  }
};

int main()
{
  int *a = (int *)malloc(sizeof(int)*5);
  for(int i=0; i<4; i++) {
    a[i] = i;
    cout << a[i] << endl;
  }

  delete(a);
  // Works fine till here..

  A b;
  cout << b.lol() << endl;
  free(b); // Causes error.     

  return 0;
}

我得到的错误是:

错误:无法将参数“1”的“A”转换为“void*”到“void” 免费(无效*)'

我无法理解为什么会这样。请解释一下。

【问题讨论】:

  • b 的类型是 A 类。它不是指针。因此,您无法释放它。
  • 首先,你实际上并没有使用new来分配b
  • 您将对象传递给free,而不是指针...
  • 如果你更正了代码,那将是未定义的行为试图在new分配的内存上使用free()(反之亦然),任何事情都可能发生.
  • delete()/free() 想要一个指针作为参数。

标签: c++ memory-management malloc free


【解决方案1】:

当你调用delete一个指针时,编译器会自动为你调用类的dtor,但free不会。 (同样new 会调用班级的ctormalloc 不会。)

在您的示例中,char 数组显然没有 dtor,因此 delete 只会返回内存。这就是为什么没关系。 (反之亦然,新建一个 char 数组,然后释放它。)

但仍然存在一个问题:如果newmalloc 从不同的堆管理器借用内存怎么办?

想象一下,你从 A 人那里借钱,然后再还给 B 人。就算你同意,你有考虑过A的感受吗?

顺便说一句,您应该使用delete [] pArray; 来释放使用new[] 分配的数组。

【讨论】:

    【解决方案2】:

    free 函数需要一个指向 malloc 分配的内存的指针。编译器只是告诉你没有给它传递一个指针,它可以很容易地证明这一事实。我猜你的意思是用 new 创建一个对象,然后在该对象的地址上调用 free 。但是你没有调用 new。

    当您更正这一点时,您很可能会发现免费成功,但您不应阅读任何此类成功的重要内容。您知道规则,它们在您的文档中明确说明。做你正在尝试的事情是不正确的。行为未定义。从这样的实验中几乎没有什么收获。您将不会了解为什么 C 内存管理函数不能与 C++ 内存管理函数配对。

    你的实验的问题是它没有力量。您可以只显示一种特定场景的结果。但这些功能旨在全面发挥作用。你将如何测试每一个可能的场景?

    永远不要使用试错法进行编程。您必须始终了解您所做的事情背后的规则和原则。

    【讨论】:

    • 这是一个原因。我的动机是想知道为什么 malloc 和 delete 不能互换使用?
    • 你的程序不会给你带来任何启示。它们不能互换,因为规范是这样说的。
    【解决方案3】:

    您没有使用new 创建b,因此您没有测试预期的假设。 (另外,b 的名称不是指针。)

    无论如何,malloc/newdelete/free 只能在它们的实现可互换的情况下互换工作。在简单的情况下和更简单的平台上,这更有可能发生,但从长远来看或作为一种习惯,这是一个冒险的赌注。

    例如,new 的数组形式,当应用于具有非平凡析构函数的类时,要求实现(编译器、运行时等)记住数组的大小,以便delete 可以调用每个数组对象的析构函数。几乎没有地方可以放置此类信息,而是在动态分配的块本身中,在new 返回的指针所指的内存位置之前。将此指针传递给free 将需要内存分配器确定分配块的实际开始,它可能会也可能无法做到。

    更一般地说,newmalloc 可能指的是完全不同的内存分配器。编译器、运行时库和操作系统协同工作,为您的程序提供内存。由于切换或升级任何这些组件,细节可能会发生变化。

    【讨论】:

      【解决方案4】:

      您的b 变量不是指针,而是堆栈分配的A。如果你想尝试这个实验,那么你想说

      A* b = new A;
      free(b);
      

      我完全赞成实验,但我不确定你想在这里实现什么。

      在 C++ 中,operator new 不仅分配内存,它还运行构造函数。同样,delete 为您运行析构函数(考虑多态类),并释放返回的内存。另一方面,malloc()free() 只是 C 库例程(从程序员的角度来看),它们只不过是从操作系统请求一块内存,然后将其返回。

      现在,对于一个简单的带有微不足道的构造函数和析构函数的 POD 类,您可能能够摆脱混合 C 和 C++ 内存分配的问题,因为没有任何特定于 C++ 的事情要做。但即使你这样做了,它又能证明什么呢?这是未定义的行为,它可能不适用于另一个编译器。明天可能就不行了。

      如果你使用任何 C++ 特性——继承、虚函数等,它肯定是行不通的,因为newdelete 必须做更多的工作,而不仅仅是分配内存。

      所以请遵守规则! :-)

      【讨论】:

        【解决方案5】:

        来自documentation,

        void free (void* ptr); 
        

        ptr::

        指向先前使用 malloc、calloc 或 重新分配。

        而且你传递的不是指针,所以它会抱怨。

         A *b = new A();
         cout << b->lol() << endl;
         free(b); // Will Not cause error
        

        【讨论】:

          【解决方案6】:

          不,您不应该混合使用 new/free 或 malloc/delete,这不是经验法则

          当然,可以使用free 放弃使用new 获得的分配而不会崩溃,但它是高度实现/系统特定的。

          忽略在某些系统上绕过析构函数或编写会损坏内存的代码这一事实,更基本、更基本的 C++ 考虑实际上就是这样:

          malloc/free 是全局的系统函数,而 new 和 delete 是 操作符

          struct X {
              void* operator new(size_t);
              void operator delete(void* object);
          };
          

          当然 - 您可以从亚马逊借一本书,然后将其还给当地图书馆:晚上去那里,然后把它放在他们家门口的台阶上。

          它将有未定义的行为,直到并包括你被捕 - 我在这里再次谈论混合新/免费 :)

          换句话说:mallocfree 处理原始内存分配,而 newdelete 处理对象,这是完全不同的事情。

          void* p = new std::vector<int>(100);
          void* q = malloc(sizeof(*q));
          

          【讨论】:

            【解决方案7】:

            已经给出了很多很好的理由。我再补充一个原因:new 运算符可以在 c++ 中被覆盖。如果他们愿意,这允许用户指定他们自己的内存管理模型。虽然这并不常见,但它的存在只是 malloc 和 new、delete 和 free 不能互换使用的又一个原因。这是@Patz 描述的原因。

            【讨论】:

            • 看起来@kfsone 打败了我
            【解决方案8】:

            free() 接受一个指针。 您正在传递一个对象(不是指针)来释放。这就是您收到错误的原因。如果您进行以下更改,您的代码可以正常工作。

            A *a = new A;
            free(a);
            

            虽然上面的代码运行良好,但会导致内存泄漏,因为free() 没有调用析构函数,析构函数负责释放构造函数创建的资源。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-12-09
              • 1970-01-01
              • 2020-02-03
              • 2014-10-23
              • 1970-01-01
              • 1970-01-01
              • 2011-02-02
              • 1970-01-01
              相关资源
              最近更新 更多