我遇到了一个我无法解决的问题。
我的问题是,如果我使用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 自由(无效*)”
我无法理解为什么会这样。请解释一下。
答案 0 :(得分:17)
当您拨打delete
指针时,编译器会自动为您调用该类的dtor
,但free
则不会。 (另外new
会拨打课程的ctor
,malloc
则不会。)
在您的示例中,char数组显然没有dtor,因此delete只会返回内存。这就是为什么它没关系。 (或者反之,新的char数组然后释放它。)
但是仍然存在一个问题:如果new
和malloc
从不同的堆管理器中借用内存会怎样?
想象一下,你向A人借钱,然后再回到B人身上。即使你对此感到满意,你有没有考虑过A的感觉?
顺便说一下,您应该使用delete [] pArray;
释放使用new[]
分配的数组。
答案 1 :(得分:6)
free函数需要一个指向malloc分配的内存的指针。编译器只是告诉你没有传递指针,这是一个很容易证明的事实。我猜你的意思是用new创建一个对象,然后在该对象的地址上调用free。但你没有打电话给新人。
当你纠正这个问题时,你可能会发现自由成功,但你不应该读到任何重要的成功。您知道规则,它们在您的文档中明确说明。做你正在尝试的事情是不正确的。行为未定义。这样的实验几乎没有什么可以获得的。您将无法了解C内存管理功能无法与C ++内存管理功能配对的原因。
你的实验存在的问题是没有力量。您可以只显示一个特定方案的结果。但这些功能旨在全面运作。您将如何测试每一种可能的情况?
绝不使用反复试验进行编程。你必须始终了解你所做的事情背后的规则和原则。
答案 2 :(得分:4)
您没有使用b
创建new
,因此您没有测试预期的假设。 (另外,b
的名称不是指针。)
无论如何,malloc
/ new
和delete
/ free
只有在它们的实现可以互换时才能互换。在简单的情况下,在更简单的平台上,这种可能性更大,但从长远来看,这是一个冒险的赌注或习惯。
例如,new
的数组形式,当应用于具有重要析构函数的类时,需要实现(编译器,运行时等)来记住数组的大小,以便{{1}可以为每个数组对象调用析构函数。几乎没有地方可以将这些信息放在动态分配的块本身中,在delete
返回的指针所引用的内存位置之前。将此指针传递给new
将需要内存分配器确定分配块的实际开始,它可能会或可能不会。
更一般地说,free
和new
可能指的是完全不同的内存分配器。编译器,运行时库和OS协同工作,为程序提供内存。由于切换或升级任何这些组件,细节可能会发生变化。
答案 3 :(得分:3)
您的b
变量不是指针,而是堆栈分配的A
。如果你想尝试这个实验,那么你想说
A* b = new A;
free(b);
我都是为了实验,但我不确定你在这里想要达到的目标。
在C ++中,operator new
不只是分配内存,它也运行构造函数。类似地,delete
为您运行析构函数(考虑多态类),以及释放返回的内存。另一方面,malloc()
和free()
只是C库例程(从程序员的角度来看),它只是从操作系统请求一块内存,然后再将其交还。
现在,对于一个简单的POD类,使用简单的构造函数和析构函数,可能能够摆脱混合C和C ++内存分配,因为没有C ++特定的东西可以完成。但即使你这样做,它证明了什么?它是未定义的行为,它可能不适用于其他编译器。明天可能行不通。
如果你使用任何C ++特性 - 继承,虚函数等等,它肯定是行不通的,因为new
和delete
除了分配内存之外还要做更多的工作
所以,请遵守规则! : - )
答案 4 :(得分:2)
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);
};
当然 - 你可以从亚马逊借一本书然后把它送回你当地的图书馆:一天晚上去那里,把它留在前门一步。
它会有不明确的行为,包括你被捕 - 我在谈论在这里再次混合新/免费:)
换句话说:malloc
和free
处理原始内存分配,而new
和delete
处理对象,这是一个非常不同的事情。
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()
没有调用析构函数,析构函数负责释放构造函数创建的资源。