C 中的 free 和 C++ 中的 delete 之间的区别?
Posted
技术标签:
【中文标题】C 中的 free 和 C++ 中的 delete 之间的区别?【英文标题】:The differences between free in C and delete in C++? 【发布时间】:2011-07-25 13:23:34 【问题描述】:我知道 C 中的 free 操作是告诉编译器这个特定的内存块是空闲的,供编译器用于进一步分配,但内存没有释放。
C++ 中的删除呢?和免费一样吗?
【问题讨论】:
是的,是一样的。但是您可以重载新/删除实现并做自己的事情***.com/q/4261963/176769 @karlphilip delete 会调用析构函数,free 不会那样做,这是一个相当大的区别 你不告诉编译器,你告诉运行时。并且内存可能会或可能不会实际返回给操作系统,具体取决于特定于实现的条件。通常小块从不断增长的堆中获得(因此被重用但不返回),而大块作为单独的实体(使用 mmap 或类似实体)从系统中获得,并在释放时返回给系统。 【参考方案1】:C++ 中有两个delete
的概念:一个是运算符,声明为::operator delete(void*)
,它基本上只是释放内存,大多数程序员通常不会考虑。另一个是删除表达式,delete p;
,其中p
是T*
。该表达式调用 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's First C++,你可以将操作符定义为malloc
/free
:
void * operator new(size_t n) return malloc(n);
void operator delete(void * p) free(p);
真正的 C++ 魔法通过 new
和 delete
表达式发生:标准的 new
表达式调用构造函数(new
表达式是 only 在分配之后调用 C++ 中的构造函数的方法!),而标准的删除表达式在释放之前调用析构函数。
为什么是“标准表达”?好吧,您还可以定义和重载许多其他版本的 new
和 delete
运算符。但是,有一个重要的不对称性:虽然您可以在自定义 new
表达式(通常称为“placement new”)中使用自定义 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'
!
为了完整起见,标准放置 new 运算符的唯一目的是调用构造函数,标准要求采用以下形式:
void * operator new(size_t, void * p) return p;
匹配delete
operator也是强制的,name什么都不做:
void operator delete(void * p, void *)
您可以在上面的一般示例中看到为什么这是必要的。
务必成对重载new
和delete
的自定义版本!原因是,如果对象构造失败并在构造函数中出现异常,则通过调用匹配有问题的new
表达式的delete
运算符来释放内存。
第二次更新:为了异常安全,我们必须考虑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);
【讨论】:
更准确地说,delete
不调用析构函数;但是编译器在找到delete
运算符的任何地方之前都会调用析构函数。当你进入delete
的函数块时,析构函数已经被调用了。
@iammilind:你的措辞有点不准确:如果你说::operator delete(p);
,析构函数将不会被调用。析构函数调用是 delete 表达式的结果。
“原始”调用序列可以像这样手动写出:T * p = (T*)::operator new(sizeof(T)); p = new (p) T; p->~T(); ::operator delete(p);
你写那个太疯狂了:-)
@Kerrek:为什么不将 cmets 添加到问题文本中?当您扩展自己的答案时,这是合适的。至于显式序列,当您为它们定义一些数据结构或分配器(如在 STL 容器的自定义分配器中)时,这一点很重要。 std::vector
之类的东西必须分配内存块,但稍后再初始化它。这不是一个人应该经常做的事情,但是当你追求表现时,你最终会需要它。
@Jan:我知道您确实在后台使用了显式分配和构造。我只是认为这超出了 OP 的兴趣范围。这也是为什么我不想在这个问题中添加operator new
替换和分配器的细节。不过,如果你愿意,我可以做到。【参考方案2】:
delete
与free
相同(ish),但有重要区别。最显着的区别是delete
将运行对象析构函数,而free
不会。
正如 cmets 所指出的,另一个非常重要的细节是不要混合 malloc/free 和 new/delete。如果您使用 malloc 分配,请使用 free,如果您使用 new,请使用 delete!
【讨论】:
使用new
分配并尝试使用free()
释放或使用malloc()
分配并尝试使用delete
释放是未定义的行为。如果您尝试这样做,某些实现会崩溃!
这样可以吗,new
=>(malloc
)=>constructor
; delete
=>destructor
=>(free
) ?其中 (malloc
,free
) 被称为“内部/自动”。我说得对吗?【参考方案3】:
它们不一样。 C++ 中的delete
运算符调用对象的析构函数,根据实现,它应该释放内存。 delete
函数也可以重载,而free
不能。
【讨论】:
不是函数,是运算符。 @Jan Hudec:非常正确。已编辑。谢谢。 @ratzip:只需调用delete
将调用该对象的默认析构函数,释放内存。
@Evan:形式上是错误的。它将调用析构函数并释放内存。它们是两个独立的步骤,后者可以通过定义适当的operator delete()
方法(以及相应的operator new()
)来覆盖每个类型。【参考方案4】:
malloc() 和 free() 不能在 C++ 代码中使用,因为它们不支持对象语义。此外,调用 free() 释放由 new 分配的对象,或使用 delete 释放由 malloc() 分配的内存的结果是未定义的。 C++ 标准不保证 operator new 的底层实现使用 malloc();事实上,在某些实现中 malloc() 和 new 使用不同的堆。 检查这个link
delete() 将删除占用的整个内存空间,一旦它被删除,在 free() 中你仍然可以访问它,就无法引用它。
【讨论】:
以上是关于C 中的 free 和 C++ 中的 delete 之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章
C++内存管理第一篇:(malloc/deldete和malloc/free)