C中的free和C ++中的删除之间的区别?
我知道C中的自由操作是告诉编译器这个特定的内存块是免费的,编译器可以用它来进一步分配,但内存没有被释放。
在C ++中删除怎么样? 和免费一样吗?
在C ++中有两种delete
概念:一种是运算符 ,声明为::operator delete(void*)
,它基本上只释放内存,而且大多数程序员通常都不会想到。 另一种是删除表达式 , delete p;
,其中p
是T*
。 该表达式调用p
指向的对象的析构函数(然后释放内存),这是C ++的一个关键语言特性,在C语言中没有模拟。
根据经验,您可以将new
表达式与delete
表达式配对,并使用free()
函数调用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 ++魔术通过new
和delete
表达式发生 :标准new
表达式在分配后调用构造函数(一个new
表达式是在C ++中调用构造函数的唯一方法!),而标准删除表达式在释放之前调用析构函数。
为什么“标准表达”? 那么,您还可以定义和重载许多其他版本的new
和delete
运算符。 但是,存在一个重要的不对称性:虽然您可以在自定义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'
!
为了完整起见, 标准要求标准放置新运算符(其唯一目的是调用构造函数)采用以下forms:
void * operator new(size_t, void * p) { return p; }
它的匹配delete
操作符也是强制命令,名称无所作为:
void operator delete(void * p, void *) { }
您可以在上面的一般示例中看到为什么这是必要的。
重要的是始终重载new
自定义版本和成对delete
! 原因是如果对象构造在构造函数内部因exception而失败,则通过调用与有问题的new
表达式匹配的delete
运算符来释放内存。
第二次更新:为了exception安全,我们必须考虑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
与free
相同(ish),但有重要区别。 最显着的区别是delete
将运行对象析构函数而free
将不运行。
正如评论所指出的,另一个非常重要的细节不是混合malloc / free和new / delete。 如果使用malloc分配,请使用free,如果使用new,则使用delete,使用delete!
他们不一样。 C ++中的delete
运算符调用对象的析构函数,根据实现,它应该释放内存。 delete
function也可以重载, free
则不能。
malloc()和free()不能在C ++代码中使用,因为它们不支持对象语义。 此外,调用free()来释放由new分配的对象,或者使用delete来释放由malloc()分配的内存的结果是未定义的。 C ++标准不保证operator new的底层实现使用malloc(); 实际上,在某些实现中,malloc()和new使用不同的堆。 检查此链接
delete()将删除占用的整个内存空间,一旦将其删除,在free()中仍然可以访问它时,引用变量是不可能的。