我在C++中看到有多种方式来分配和释放数据,我知道当你打电话给malloc
你时应该打电话free
,当你使用new
操作员时你应该配对,delete
将两者混合是错误的(例如,调用free()
创建的东西)与new
操作员),但我不知道何时应该使用malloc
/ free
何时应该在我的真实世界程序中使用new
/ delete
.
如果您是C++专家,请告诉我您在此方面遵循的任何经验法则或惯例.
除非你被迫使用C,否则你永远不 应该使用malloc
.一直用new
.
如果您需要大量数据,请执行以下操作:
char *pBuffer = new char[1024];
虽然这不正确但要小心:
//This is incorrect - may delete only one element, may corrupt the heap, or worse... delete pBuffer;
相反,您应该在删除数据数组时执行此操作:
//This deletes all items in the array delete[] pBuffer;
该new
关键字是做它的C++的方式,这将确保你的类型都会有所谓的构造.该new
关键字也更加类型安全,而malloc
不是类型安全的.
malloc
如果您需要更改数据缓冲区的大小,我认为唯一有益于使用的方法就是使用它.该new
关键字没有像类似的方式realloc
.该realloc
函数可能能够更有效地扩展一块内存的大小.
值得一提的是你不能混用new
/ free
和malloc
/ delete
.
注意:此问题中的某些答案无效.
int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5 int* p_array = new int[5]; // Creates 5 elements
简短的回答是:如果没有malloc
充分的理由,请不要使用C++.malloc
与C++一起使用时有许多不足之处,C++ new
被定义为可以克服.
malloc
以任何有意义的方式都不是类型安全的.在C++中,您需要转换来自void*
.这可能会引入很多问题:
#includestruct foo { double d[5]; }; int main() { foo *f1 = malloc(1); // error, no cast foo *f2 = static_cast (malloc(sizeof(foo))); foo *f3 = static_cast (malloc(1)); // No error, bad }
但它比这更糟糕.如果有问题的类型是POD(普通旧数据),那么你可以半合理地使用它malloc
来为它分配内存,就像f2
第一个例子中那样.
如果一个类型是POD,那就不那么明显了.事实上,给定类型可能从POD更改为非POD而没有产生编译器错误并且可能非常难以调试问题是一个重要因素.例如,如果有人(可能是另一个程序员,在维护期间,很久以后要做出导致foo
不再是POD 的更改,那么在编译时不会出现明显的错误,例如:
struct foo { double d[5]; virtual ~foo() { } };
将使malloc
中f2
也变得不好,没有任何明显的诊断.这里的示例是微不足道的,但是可能会意外地将非PODness引入更远的地方(例如,在基类中,通过添加非POD成员).如果您有C++ 11/boost,您可以使用它is_pod
来检查这个假设是否正确,如果不是,则会产生错误:
#include#include foo *safe_foo_malloc() { static_assert(std::is_pod ::value, "foo must be POD"); return static_cast (malloc(sizeof(foo))); }
虽然boost 无法确定某个类型是否为没有C++ 11或其他编译器扩展的POD.
malloc
NULL
如果分配失败则返回.new
会扔std::bad_alloc
.稍后使用NULL
指针的行为是未定义的.抛出异常时会出现干净的语义,并且会从错误源中抛出异常.malloc
在每次通话时使用适当的测试进行包装似乎很乏味且容易出错.(你只需要忘记一次撤消所有好的工作).可以允许异常传播到调用者能够合理地处理它的级别,其中NULL
更有意义地传递回来.我们可以扩展我们的safe_foo_malloc
函数来抛出异常或退出程序或调用一些处理程序:
#include#include void my_malloc_failed_handler(); foo *safe_foo_malloc() { static_assert(std::is_pod ::value, "foo must be POD"); foo *mem = static_cast (malloc(sizeof(foo))); if (!mem) { my_malloc_failed_handler(); // or throw ... } return mem; }
从根本上说malloc
是C功能并且new
是C++功能.结果malloc
不能很好地与构造函数一起使用,它只关注分配一块字节.我们可以safe_foo_malloc
进一步扩展我们的使用位置new
:
#include#include void my_malloc_failed_handler(); foo *safe_foo_malloc() { void *mem = malloc(sizeof(foo)); if (!mem) { my_malloc_failed_handler(); // or throw ... } return new (mem)foo(); }
我们的safe_foo_malloc
功能不是很通用 - 理想情况下我们想要的东西可以处理任何类型,而不仅仅是foo
.我们可以使用非默认构造函数的模板和可变参数模板实现此目的:
#include#include #include void my_malloc_failed_handler(); template struct alloc { template static T *safe_malloc(Args&&... args) { void *mem = malloc(sizeof(T)); if (!mem) { my_malloc_failed_handler(); // or throw ... } return new (mem)T(std::forward(args)...); } };
现在虽然在解决我们到目前为止确定的所有问题时,我们实际上已经彻底改造了默认new
运营商.如果您打算使用malloc
和放置,new
那么您也new
可以开始使用!
来自C++ FQA Lite:
[16.4]为什么我应该使用new而不是值得信赖的旧malloc()?
FAQ:new/delete调用构造函数/析构函数; new是类型安全的,malloc不是; new可以被类覆盖.
FQA:FAQ提到的新的优点不是美德,因为构造函数,析构函数和运算符重载都是垃圾(看看没有垃圾收集会发生什么?),类型安全问题在这里很小(通常你有)将malloc返回的void*转换为右指针类型,将其分配给一个类型化的指针变量,这可能很烦人,但远非"不安全").
哦,使用值得信赖的旧malloc可以使用同样值得信赖的旧realloc.太糟糕了,我们没有一个闪亮的新操作员更新或什么.
尽管如此,即使语言是C++,新的也不足以证明偏离整个语言使用的共同风格是正确的.特别是,如果只是对象进行malloc操作,那么具有非平凡构造函数的类将会以致命的方式行为异常.那么为什么不在整个代码中使用新的呢?人们很少会将操作员重新设置为新的,所以它可能不会过多地妨碍你.如果他们确实过载新的,你总是可以让他们停下来.
对不起,我无法抗拒.:)
始终在C++中使用new.如果需要一个无类型内存块,可以直接使用operator new:
void *p = operator new(size); ... operator delete(p);
使用malloc
并只用于分配要由C-中心库和API来管理内存.对您控制的所有内容使用和(以及变体).free
new
delete
[]
new vs malloc()
1)new
是一个操作员,同时malloc()
也是一个功能.
2)new
调用构造函数,而不调用malloc()
.
3)new
返回确切的数据类型,同时malloc()
返回void*.
4)new
将不会返回NULL(将抛出失败),而malloc()
返回NULL
5)的存储器再分配不通过处理new
而malloc()
可以
要回答你的问题,你应该知道的区别malloc
和new
.区别很简单:
malloc
分配内存,同时new
分配内存并调用你正在为其分配内存的对象的构造函数.
因此,除非您被限制为C,否则不应使用malloc,尤其是在处理C++对象时.这将是破坏你的程序的一个秘诀.
此外之间的差别free
,并delete
是完全一样的.区别在于delete
除了释放内存之外还将调用对象的析构函数.
malloc
和之间有一个很大的区别new
.malloc
分配内存.这对于C来说很好,因为在C中,一块内存是一个对象.
在C++中,如果您不处理POD类型(类似于C类型),则必须在内存位置调用构造函数以实际拥有对象.非POD类型在C++中非常常见,因为许多C++特性使对象自动成为非POD.
new
分配内存并在该内存位置创建一个对象.对于非POD类型,这意味着调用构造函数.
如果您这样做:
non_pod_type* p = (non_pod_type*) malloc(sizeof *p);
您获取的指针无法解除引用,因为它不指向对象.在使用之前,您需要在其上调用构造函数(这是使用展示位置完成的new
).
另一方面,如果你这样做:
non_pod_type* p = new non_pod_type();
你得到一个始终有效的指针,因为new
创建了一个对象.
即使对于POD类型,两者之间也存在显着差异:
pod_type* p = (pod_type*) malloc(sizeof *p); std::cout << p->foo;
这段代码会打印一个未指定的值,因为创建的POD对象malloc
未初始化.
使用new
,您可以指定要调用的构造函数,从而获得明确定义的值.
pod_type* p = new pod_type(); std::cout << p->foo; // prints 0
如果你真的想要它,你可以使用use new
来获得未初始化的POD对象.有关详细信息,请参阅此其他答案.
另一个区别是失败时的行为.当它无法分配内存时,malloc
返回空指针,同时new
抛出异常.
前者要求您在使用之前测试返回的每个指针,而后者将始终生成有效的指针.
出于这些原因,您应该使用C++代码new
,而不是malloc
.但即便如此,您也不应该使用new
"公开",因为它会获取您稍后需要释放的资源.使用时new
,应将其结果立即传递到资源管理类:
std::unique_ptrp = std::unique_ptr (new T()); // this won't leak
有一些事情new
没有malloc
做到:
new
通过调用该对象的构造函数来构造对象
new
不需要对已分配的内存进行类型转换.
它不需要分配大量内存,而是需要构造许多对象.
所以,如果你使用malloc
,那么你需要明确地做上面的事情,这并不总是实际的.另外,new
可以重载但malloc
不能.
如果您使用不需要构造/销毁并且需要重新分配的数据(例如,大量的int),那么我相信malloc / free是一个不错的选择,因为它可以为您提供重新分配,这比new-memcpy更快-delete(在我的Linux机器上,但是我想这可能取决于平台)。如果使用不是POD且需要构造/销毁的C ++对象,则必须使用new和delete运算符。
无论如何,我不明白为什么不应该同时使用两种方法(前提是您释放了已分配的内存并删除了用new分配的对象),如果可以利用速度提升的优势(如果您要重新分配大型数组,有时会很重要)重新分配可以给您的POD)。
除非您需要,否则应坚持使用C ++中的new / delete。