在什么情况下,我使用malloc vs新?
我看到在C + +有多种方式来分配和释放数据,我明白,当你打电话给malloc
你应该free
打电话,当你使用new
运营商,你应该与delete
配对,这是一个错误混合两者(例如free()
呼叫free()
用new
运算符创build的东西),但我不清楚什么时候应该使用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 ++的方式,它将确保你的types有他们的构造函数调用 。 new
关键字也是更安全的types,而malloc
根本不是types安全的。
如果你需要改变你的数据缓冲区的大小,唯一的办法就是使用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 ++代码修正了缺陷
-
malloc
不是以任何有意义的方式安全的。 在C ++中,你需要从void*
返回。 这可能会带来很多问题:#include <stdlib.h> struct foo { double d[5]; }; int main() { foo *f1 = malloc(1); // error, no cast foo *f2 = static_cast<foo*>(malloc(sizeof(foo))); foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad }
-
这比这还糟糕。 如果问题的types是POD(普通的旧数据),那么你可以半理智地使用
malloc
来为它分配内存,就像第一个例子中的f2
那样。虽然types是POD,但并不是那么明显。 事实上,一个给定的types可能会从POD变成非POD,而不会导致编译器错误,并且可能很难debugging问题,这是一个重要的因素。 例如,如果有人(可能是另一个程序员,在维护期间,很多时候会做出一个改变,导致
foo
不再是POD,那么编译时就不会出现明显的错误,例如:struct foo { double d[5]; virtual ~foo() { } };
会使
f2
的malloc
也变坏,没有任何明显的诊断。 这里的例子是微不足道的,但是可能偶然地将非PODness引入得更远(例如,在基类中,通过添加非POD成员)。 如果你有C ++ 11 / boost,你可以使用is_pod
来检查这个假设是否正确,如果不是这样的话会产生一个错误:#include <type_traits> #include <stdlib.h> foo *safe_foo_malloc() { static_assert(std::is_pod<foo>::value, "foo must be POD"); return static_cast<foo*>(malloc(sizeof(foo))); }
尽pipeboost 不能确定一个types是否是没有C ++ 11或其他编译器扩展的POD 。
-
如果分配失败,
malloc
返回NULL
。new
会抛出std::bad_alloc
。 稍后使用NULL
指针的行为是未定义的。 抛出exception时具有干净的语义,并且从错误源抛出exception。 在每次调用时用适当的testing对malloc
进行包装看起来很乏味且容易出错。 (你只需要忘记一次就可以撤消所有的好工作)。 可以允许exception传播到调用者能够合理地处理它的级别,其中NULL
很难有意传回。 我们可以扩展我们的safe_foo_malloc
函数来抛出exception或退出程序或调用一些处理程序:#include <type_traits> #include <stdlib.h> void my_malloc_failed_handler(); foo *safe_foo_malloc() { static_assert(std::is_pod<foo>::value, "foo must be POD"); foo *mem = static_cast<foo*>(malloc(sizeof(foo))); if (!mem) { my_malloc_failed_handler(); // or throw ... } return mem; }
-
从根本上讲,
malloc
是一个C特性,而new
是一个C ++特性。 因此,malloc
不能很好地与构造函数一起玩,只会分配一大块字节。 我们可以进一步扩展我们的safe_foo_malloc
以使用new
位置:#include <stdlib.h> #include <new> 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
函数不是非常通用的 – 理想情况下,我们希望能够处理任何types的东西,而不仅仅是foo
。 我们可以使用非默认构造函数的模板和可变参数模板来实现:#include <functional> #include <new> #include <stdlib.h> void my_malloc_failed_handler(); template <typename T> struct alloc { template <typename ...Args> 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)...); } };
现在,虽然在解决所有我们确定的问题,我们已经实际上重新创build了默认的
new
运算符。 如果你打算使用malloc
和placementnew
那么你可以使用new
来开始!
从C ++ FQA Lite :
[16.4]为什么我应该使用new而不是可靠的旧malloc()?
FAQ:new / delete调用构造函数/析构函数; 新是types安全的,malloc不是; 新的可以被一个类覆盖。
FQA:FAQ提到的新function不是美德,因为构造函数,析构函数和运算符重载是垃圾(看看没有垃圾回收会发生什么?),types安全问题在这里非常小(通常你有将malloc返回的void *转换为正确的指针types,将其分配给一个types化的指针variables,这可能很烦人,但远离“不安全”)。
哦,使用可靠的旧malloc使得使用同样值得信赖和旧的realloc成为可能。 太糟糕了,我们没有一个shiny的新运营商更新或什么。
尽pipe如此,即使语言是C ++,新的语言也不足以certificate与一种语言使用的通用风格的偏差。 特别是,如果你只是简单地使用malloc对象,那么带有不平凡构造函数的类将会以致命的方式行事不端。 那么为什么不在代码中使用新的? 人们很less重载运营商新的,所以它可能不会太多。 如果他们超载新的,你总是可以要求他们停止。
对不起,我无法抗拒。 🙂
总是在C ++中使用新的。 如果你需要一个无types的内存块,你可以直接使用operator new:
void *p = operator new(size); ... operator delete(p);
使用malloc
并仅用于分配要由c-centric库和APIpipe理的内存。 使用new
和delete
(和[]
变种)为你控制的一切。
新vs malloc()
1) new
是一个运算符 ,而malloc()
是一个函数 。
2) new
调用构造函数 ,而malloc()
不。
3) new
返回确切的数据types ,而malloc()
返回void * 。
4) new
从不返回NULL (将抛出失败),而malloc()
返回NULL
5) malloc()
可以重新分配不被new
处理的内存
malloc
和new
之间有一个很大的区别。 malloc
分配内存。 对C来说这很好,因为在C中,一块内存是一个对象。
在C ++中,如果不处理PODtypes(类似于Ctypes),则必须调用内存位置上的构造函数以在其中实际存在对象。 非PODtypes在C ++中非常常见,因为许多C ++特性自动使对象成为非POD。
new
分配内存并在该内存位置创build一个对象。 对于非PODtypes,这意味着调用构造函数。
如果你做这样的事情:
non_pod_type* p = (non_pod_type*) malloc(sizeof *p);
您获得的指针不能被取消引用,因为它不指向对象。 在使用它之前,您需要先调用一个构造函数(这是使用new
位置完成的)。
另一方面,如果你这样做:
non_pod_type* p = new non_pod_type();
你得到一个总是有效的指针,因为new
了一个对象。
即使是PODtypes,两者之间也存在显着差异:
pod_type* p = (pod_type*) malloc(sizeof *p); std::cout << p->foo;
这段代码将打印一个未指定的值,因为由malloc
创build的POD对象不会被初始化。
用new
,你可以指定一个构造函数来调用,从而得到一个定义好的值。
pod_type* p = new pod_type(); std::cout << p->foo; // prints 0
如果你真的想要它,你可以使用new
来获得未初始化的POD对象。 有关更多信息,请参阅其他答案 。
另一个区别是失败后的行为。 当它分配内存失败时, malloc
返回一个空指针,而new
抛出一个exception。
前者要求你在使用之前testing每一个返回的指针,而后者将始终产生有效的指针。
由于这些原因,在C ++代码中你应该使用new
,而不是malloc
。 但即使如此,你也不应该使用new
“公开”,因为它获得了你以后需要发布的资源。 当你使用new
你应该把它的结果立即传递给一个资源pipe理类:
std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
有一些malloc
没有做的new
事情:
-
new
通过调用该对象的构造函数来构造该对象 -
new
不需要分配内存的types转换。 - 它不需要分配大量的内存,而是需要构build大量的对象。
所以,如果你使用malloc
,那么你需要明确地做以上的事情,这并不总是实际的。 另外, new
可以被重载,但是malloc
不可以。
要回答你的问题,你应该知道malloc
和new
之间的区别 。 区别很简单:
malloc
分配内存 ,而new
分配内存和调用你分配内存的对象的构造函数 。
所以,除非你被限制在C,否则不应该使用malloc,特别是在处理C ++对象的时候。 这将是一个打破你的程序的秘诀。
free
和delete
的区别也是一样的。 不同之处在于,除了释放内存之外, delete
还会调用对象的析构函数。
如果你正在使用c ++,那么尝试使用新/删除而不是malloc / calloc,因为它们是运算符,而它们自己与malloc / calloc相比,因为它们用于包含另一个头文件。因此,不要在单个编码中混合使用两种不同的语言他们的工作方式都是相似的,都是从哈希表中的堆段dynamic地分配内存。
如果你有C代码,你可以把它移到malloc()中。 对于任何新的C ++代码,我build议使用新的代替。
如果你使用的数据不需要构造/销毁,并且需要重新分配(例如,大量的整数),那么我相信malloc / free是一个不错的select,因为它可以让你realloc,这比new-memcpy – 删除(这是在我的Linux机器上,但我想这可能是平台依赖)。 如果您使用不是POD的C ++对象并需要构build/销毁,那么您必须使用新的和删除操作符。
无论如何,我不明白为什么你不应该同时使用(假设你释放你的malloced内存和删除分配新的对象),如果可以利用的速度提升(有时是一个重要的,如果你重新分配大型数组的POD)realloc可以给你。
除非你需要它,否则你应该坚持在C ++中新build/删除。
从较低的angular度来看,new将在给出内存之前初始化所有内存,而malloc将保留内存的原始内容。
new
将初始化结构的默认值,并正确地将其中的引用链接到它自己。
例如
struct test_s { int some_strange_name = 1; int &easy = some_strange_name; }
所以new struct test_s
将会返回一个初始化结构和一个工作引用,而malloc'ed版本没有默认值,并且内部引用不会被初始化。
new
和delete
操作符可以对类和结构进行操作,而malloc
和free
只能处理需要被转换的内存块。
使用new/delete
将有助于改进代码,因为您不需要将分配的内存转换为所需的数据结构。
罕见的情况下,考虑使用malloc / free而不是新/删除是当您分配,然后重新分配(简单的podtypes,而不是对象)使用realloc,因为没有类似的function,在C ++ realloc(虽然这可以使用更多的C ++方法)
在下面的情况下,我们不能使用新的,因为它调用构造函数。
class B { private: B *ptr; int x; public: B(int n) { cout<<"B: ctr"<<endl; //ptr = new B; //keep calling ctr, result is segmentation fault ptr = (B *)malloc(sizeof(B)); x = n; ptr->x = n + 10; } ~B() { //delete ptr; free(ptr); cout<<"B: dtr"<<endl; } };
malloc()用于在C中dynamic分配内存,而c ++中的new()完成相同的工作。 所以你不能混合两种语言的编码惯例。 如果你要求calloc和malloc()之间的区别