In what cases do I use malloc vs new?
我在C++中看到了分配和释放数据的多种方法,我知道当你调用EDCOX1,0的时候,你应该调用EDCOX1,1,当你使用EDCOX1,2的操作符时,你应该用EDCOX1,3来配对,这是一个错误,把两个混合起来(例如,调用EDCOX1,4),用EDCOX1(2)操作符创建的东西,但我不清楚我在现实生活中什么时候应该使用
如果你是C++专家,请让我知道你在这方面遵循的任何规则或惯例。
除非你被迫使用c,否则你不应该使用
如果您需要大量数据,只需执行以下操作:
1 | char *pBuffer = new char[1024]; |
尽管这不正确,但要小心:
1 2 | //This is incorrect - may delete only one element, may corrupt the heap, or worse... delete pBuffer; |
相反,在删除数据数组时应该这样做:
1 2 | //This deletes all items in the array delete[] pBuffer; |
EDCOX1的1 }关键字是C++的方式,它将确保您的类型将调用它的构造函数。
我认为使用
值得一提的是,你不能把
注意:此问题中的某些答案无效。
1 2 | int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5 int* p_array = new int[5]; // Creates 5 elements |
简短的回答是:对于C++,不要使用EDCOX1 0,没有这样做的充分理由。EDCOX1的0度在使用C++时有许多不足之处,定义了EDCOX1×2定义来克服。
新的C++代码缺陷1 2 3 4 5 6 7 8 9 10 11 | #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 } |
但比这更糟。如果所讨论的类型是pod(普通的旧数据),那么您可以半明智地使用
不过,如果一种类型是pod,就不那么明显了。事实上,给定类型可能从POD更改为非POD,但不会导致编译器错误,并且可能很难调试问题,这是一个重要因素。例如,如果有人(可能是另一个程序员,在维护期间,很晚才进行了一次更改,导致
1 2 3 4 | struct foo { double d[5]; virtual ~foo() { } }; |
会使
1 2 3 4 5 6 7 | #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))); } |
虽然Boost无法确定一个类型是否是没有C++ 11或其他编译器扩展的POD。
如果分配失败,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #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; } |
从根本上说,
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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(); } |
我们的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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)...); } }; |
现在,尽管在解决我们目前发现的所有问题时,我们实际上已经重新设计了默认的
从C++ FQA Lite:
[16.4] Why should I use new instead of
trustworthy old malloc()?FAQ: new/delete call the
constructor/destructor; new is type
safe, malloc is not; new can be
overridden by a class.FQA: The virtues of new mentioned by
the FAQ are not virtues, because
constructors, destructors, and
operator overloading are garbage (see
what happens when you have no garbage
collection?), and the type safety
issue is really tiny here (normally
you have to cast the void* returned by
malloc to the right pointer type to
assign it to a typed pointer variable,
which may be annoying, but far from
"unsafe").Oh, and using trustworthy old malloc
makes it possible to use the equally
trustworthy & old realloc. Too bad we
don't have a shiny new operator renew or something.Still, new is not bad enough to
justify a deviation from the common
style used throughout a language, even
when the language is C++. In
particular, classes with non-trivial
constructors will misbehave in fatal
ways if you simply malloc the objects.
So why not use new throughout the
code? People rarely overload operator
new, so it probably won't get in your
way too much. And if they do overload
new, you can always ask them to stop.
对不起,我就是忍不住。:)
在C++中总是使用新的。如果需要非类型化内存块,可以直接使用operator new:
1 2 3 | void *p = operator new(size); ... operator delete(p); |
使用
美国vs malloc()
1)
2)constructors
3)
4)
5)reallocation内存处理
在回答你的问题,你应该知道
所以,除非你限制到C,你应该永远不会使用malloc,尤其是当处理与C + +对象。a recipe for是破你的计划。
因此,之间的差别相当
在C++中,如果不处理POD类型(类似于C类型),则必须调用内存位置上的构造函数来实际存在对象。在C++中,非POD类型是非常常见的,因为许多C++特性使对象自动非POD。
如果你这样做:
1 | non_pod_type* p = (non_pod_type*) malloc(sizeof *p); |
无法取消引用您获得的指针,因为它没有指向对象。在使用它之前,您需要对它调用一个构造函数(这是使用placement
另一方面,如果你:
1 | non_pod_type* p = new non_pod_type(); |
您得到一个始终有效的指针,因为
即使是吊舱类型,两者之间也存在显著差异:
1 2 | pod_type* p = (pod_type*) malloc(sizeof *p); std::cout << p->foo; |
这段代码将打印一个未指定的值,因为
使用
1 2 | pod_type* p = new pod_type(); std::cout << p->foo; // prints 0 |
如果你真的想要它,你可以使用
另一个区别是失败时的行为。当它无法分配内存时,
前者要求您在使用前测试返回的每个指针,而后者总是生成有效的指针。
由于这些原因,在C++代码中,您应该使用EDCOX1×1,而不是EDCOX1×0。但即便如此,您也不应该在"公开"中使用
1 | std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak |
所以,如果你使用
如果您使用的数据不需要构造/销毁,需要重新分配(例如,大量整数),那么我认为malloc/free是一个不错的选择,因为它可以给您重新分配,这比新的memcpy删除快得多(它在我的Linux设备上,但我猜这可能取决于平台)。如果使用C++对象而不是POD,需要构建/销毁,那么必须使用新的和删除运算符。
不管怎样,我不明白为什么你不应该同时使用这两种方法(前提是你释放了你的内存错误并删除了新分配的对象),如果你能利用重新分配给你的速度提升(有时是一个重要的,如果你重新分配了大量的pod数组)。
除非你需要它,否则你应该坚持C++中的Neal/Delphi。
如果你有C代码要移植到C++,你可能会在其中留下任何的MalCube()调用。对于任何新的C++代码,我建议使用新的代码。
如果使用C++,则尝试使用Neal/Delphi,而不是MALOC/CALLC,因为它们是运算符。对于malloc/calloc,需要包含另一个头。不要在同一代码中混合使用两种不同的语言。它们的工作在各个方面都很相似,都从哈希表的堆段动态分配内存。
从较低的角度来看,new将在提供内存之前初始化所有内存,而malloc将保留内存的原始内容。
例如
1 2 3 4 | struct test_s { int some_strange_name = 1; int &easy = some_strange_name; } |
在这样的结构
动态分配是只有当生命所需的时间应比对象的范围不同(它会创建在本持有范围较小。也使你有一个更大的原因)和特异性的价值在保它不工作。
例如:
1 2 3 4 5 6 7 | std::vector<int> *createVector(); // Bad std::vector<int> createVector(); // Good auto v = new std::vector<int>(); // Bad auto result = calculate(/*optional output = */ v); auto v = std::vector<int>(); // Good auto result = calculate(/*optional output = */ &v); |
从11在C + +,我们
(这是需要变成:
1 2 3 4 | auto instance = std::make_unique<Class>(/*args*/); // C++14 auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11 auto instance = std::make_unique<Class[]>(42); // C++14 auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11 |
17所以C + +类,你需要
1 2 3 | auto optInstance = std::optional<Class>{}; if (condition) optInstance = Class{}; |
他很快的"实例"的形式去了,他们的工作记忆的人。这是一个简单的所有权的转移:
1 2 3 | auto vector = std::vector<std::unique_ptr<Interface>>{}; auto instance = std::make_unique<Class>(); vector.push_back(std::move(instance)); // std::move -> transfer (most of the time) |
当你需要
1 2 3 4 | auto instance = std::make_unique<Class>(); legacyFunction(instance.release()); // Ownership being transferred auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr |
C++ 98/03中,你需要做的手动内存管理。如果你在这个个案,尝试升级到一个新版本的标准。如果你正在粉刷:
1 2 3 4 | auto instance = new Class(); // Allocate memory delete instance; // Deallocate auto instances = new Class[42](); // Allocate memory delete[] instances; // Deallocate |
确保你在正确的轨道有一个没有任何内存泄漏!Don’t move语义带来的任何工作。
所以,当我们需要做malloc在C + +?唯一的原因,将有效信息通过内存分配和初始化后,置入新的。
1 2 3 4 | auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory auto instance = new(instanceBlob)Class{}; // Initialize via constructor instance.~Class(); // Destroy via destructor std::free(instanceBlob); // Deallocate the memory |
就好了,上面的是有效的,这可以通过一个新的算子做为好。
最后,我们有一个安静的房间里的大象:
如果你忘了这一案例,虚拟函数、类成员函数。它是只允许在一个吊舱的结构。
一些例外的规则:
- 你是写一个标准库的高级数据结构是适当的WHERE malloc
- 你有一个大的分配数量的内存(内存拷贝a 10GB的文件?)
- 你要防止你使用某些模具结构
- 你不需要店型
使用
考虑到罕见的病例使用malloc /自由/删除是不是新的,当你allocating然后reallocating(POD类型简单,需要的对象)使用realloc AS没有类似realloc函数在C + +(我本可以做更多的用C + +方法)。
在下面的场景中,我们不能使用new,因为它调用构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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中动态分配内存而同样的工作是用C++中的New()完成的。因此,不能混合使用两种语言的编码约定。如果你问一下calloc和malloc()之间的区别就好了。