C中的free和C ++中的删除之间的区别?

时间:2011-07-25 13:23:34

标签: c free delete-operator

我知道 C 中的自由操作是告诉编译器这个特定的内存块可以免费供编译器用于进一步分配,但是内存没有被释放。

C ++中的删除怎么样?和免费一样吗?

4 个答案:

答案 0 :(得分:19)

C ++中有两个delete概念:一个是运算符,声明为::operator delete(void*),基本上只释放内存,通常不会考虑大多数程序员。另一个是删除表达式delete p;,其中pT*。该表达式调用p指向的对象的析构函数(然后释放内存),这是C ++的一个关键语言特性,在C中没有模拟。

根据经验,您将new个表达式与delete个表达式配对,将malloc()个函数调用与free()个函数调用配对:

T * p = new T;        // constructor called!
delete p;             // destructor called!

void * x = malloc(5); // just raw memory
free(x);              // freed

高级部分(不响应OP的问题)

C ++中的动态对象生存期遵循以下一般模式:分配,构造,销毁,解除分配。标准new表达式执行分配和构造,而标准delete表达式执行销毁和释放。

您可以手动写出该过程:

T * p = (T*)::operator new(sizeof(T));   // allocate raw memory
p = new (p) T;                           // call the constructor ("placement new")

/*...*/

p->~T();                                 // destroy the object
::operator delete(p);                    // deallocate the memory

事实上,如果您真的想要实现Baby的First C ++,您可以将运算符定义为malloc / free

void * operator new(size_t n) { return malloc(n); }
void   operator delete(void * p) { free(p); }

真正的C ++魔法凭借newdelete 表达式发生:标准new表达式调用构造函数(new expression是分配后调用C ++中构造函数的唯一方法!)而标准delete表达式在释放之前调用析构函数。

为什么“标准表达”?好吧,您还可以定义和重载newdelete运算符的许多其他版本。但是,存在一个重要的不对称:虽然您可以在自定义new表达式中使用自定义new运算符(通常称为“placement new”),但没有等效的“placement-delete”表达式。因此,无论何时使用自定义new表达式,都必须在调用匹配的自定义删除运算符之前手动调用析构函数:

T * p = new (A, B, C) T;                          // some custom new expression

// Entirely equivalent version:

T * p = (T*) ::operator new(sizeof(T), A, B, C);  // this is your custom overload
T * p = new (p) T;                                // std. placement-new expression calls constructor

/* ---- later ---- */

p->~T();                                          // Must destroy manually!
::operator delete(p, A, B, C);                    // your matching custom overload

请注意,不存在自定义删除表达式delete (A,B,C) p'

为了完整性,标准要求标准放置新运算符(其唯一目的是调用构造函数)采用以下形式:

void * operator new(size_t, void * p) { return p; }

匹配delete 运算符也是强制性的,名称不做任何事情:

void operator delete(void * p, void *) { }

您可以在上面的一般示例中看到为什么这是必要的。

始终要成对地重载newdelete的自定义版本非常重要!原因是如果对象构造因构造函数内部的异常而失败,则通过调用delete运算符来释放内存,该运算符与有问题的new表达式匹配。


第二次更新:为了保护异常,我们必须考虑T的构造函数可能会抛出:

版本1:

try {
  T * p = new (A, B, C) T;
  /* ... */
  p->~T();
  ::operator delete(p, A, B, C); // automatically invoked if T::T() throws!
}
catch(...) { }

第2版:

void * addr = ::operator new(sizeof(T), A, B, C);
try {
  T * p = new (addr) T;  // might throw
  /* ... */
  p->~T();
  // ::operator delete(p, addr); // ditto as in (1), but does nothing
}
catch(...) { }
::operator delete(addr, A, B, C);

答案 1 :(得分:2)

deletefree相同(ish),但有重要差异。最显着的区别是delete将运行对象析构函数,而free则不会。

正如评论所指出的,另一个非常重要的细节不是混合malloc / free和new / delete。如果使用malloc分配,请使用free,如果使用new,则使用delete,使用delete!

答案 2 :(得分:0)

他们不一样。 C ++中的delete运算符调用对象的析构函数,根据实现,它应该释放内存。 delete函数也可以重载,而free则不能。

答案 3 :(得分:0)

malloc()和free()不能在C ++代码中使用,因为它们不支持对象语义。此外,调用free()来释放由new分配的对象,或者使用delete来释放由malloc()分配的内存的结果是未定义的。 C ++标准不保证operator new的底层实现使用malloc();实际上,在某些实现中,malloc()和new使用不同的堆。 请检查此link

delete()将删除占用的整个内存空间,一旦将其删除,在free()中仍然可以访问它时,引用变量是不可能的。