如果使用malloc分配的内存使用delete而不是free来删除

时间:2013-12-10 07:12:33

标签: c++ memory-management malloc free

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

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

  

如果我们使用 malloc 分配内存,则应使用免费删除内存。

     

如果我们使用分配内存,则应使用删除删除内存。

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

#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   自由(无效*)”

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

8 个答案:

答案 0 :(得分:17)

当您拨打delete指针时,编译器会自动为您调用该类的dtor,但free则不会。 (另外new会拨打课程的ctormalloc则不会。)

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

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

想象一下,你向A人借钱,然后再回到B人身上。即使你对此感到满意,你有没有考虑过A的感觉?

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

答案 1 :(得分:6)

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

当你纠正这个问题时,你可能会发现自由成功,但你不应该读到任何重要的成功。您知道规则,它们在您的文档中明确说明。做你正在尝试的事情是不正确的。行为未定义。这样的实验几乎没有什么可以获得的。您将无法了解C内存管理功能无法与C ++内存管理功能配对的原因。

你的实验存在的问题是没有力量。您可以只显示一个特定方案的结果。但这些功能旨在全面运作。您将如何测试每一种可能的情况?

绝不使用反复试验进行编程。你必须始终了解你所做的事情背后的规则和原则。

答案 2 :(得分:4)

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

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

例如,new的数组形式,当应用于具有重要析构函数的类时,需要实现(编译器,运行时等)来记住数组的大小,以便{{1}可以为每个数组对象调用析构函数。几乎没有地方可以将这些信息放在动态分配的块本身中,在delete返回的指针所引用的内存位置之前。将此指针传递给new将需要内存分配器确定分配块的实际开始,它可能会或可能不会。

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

答案 3 :(得分:3)

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

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

我都是为了实验,但我不确定你在这里想要达到的目标。

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

现在,对于一个简单的POD类,使用简单的构造函数和析构函数,可能能够摆脱混合C和C ++内存分配,因为没有C ++特定的东西可以完成。但即使你这样做,它证明了什么?它是未定义的行为,它可能不适用于其他编译器。明天可能行不通。

如果你使用任何C ++特性 - 继承,虚函数等等,它肯定是行不通的,因为newdelete除了分配内存之外还要做更多的工作

所以,请遵守规则! : - )

答案 4 :(得分:2)

来自documentation,

void free (void* ptr); 

<强> PTR ::

  

指向先前使用malloc,calloc或分配的内存块的指针   的realloc。

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

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

答案 5 :(得分:1)

不, 经验法则你不应该混合使用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));

答案 6 :(得分:1)

已经有很多好的理由。我还要补充一个原因:new运算符可以在c ++中重写。这允许用户根据需要指定他们自己的存储器管理模型。虽然这是非常罕见的,但它的存在只是malloc和new,delete和free不能互换使用的另一个原因。这是出于@Patz描述的原因。

答案 7 :(得分:0)

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

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

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