C++ 在什么情况下我使用 malloc 和/或 new?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/184537/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In what cases do I use malloc and/or new?
提问by
I see in C++ there are multiple ways to allocate and free data and I understand that when you call malloc
you should call free
and when you use the new
operator you should pair with delete
and it is a mistake to mix the two (e.g. Calling free()
on something that was created with the new
operator), but I'm not clear on when I should use malloc
/ free
and when I should use new
/ delete
in my real world programs.
我在 C++ 中看到有多种方法来分配和释放数据,我知道当你打电话时malloc
你应该打电话free
,当你使用new
运营商时你应该配对,delete
混合这两者是错误的(例如,调用free()
创建的东西与new
操作员),但我不清楚我什么时候应该在现实世界的程序中使用malloc
/free
以及什么时候应该使用new
/ delete
。
If you're a C++ expert, please let me know any rules of thumb or conventions you follow in this regard.
如果您是 C++ 专家,请告诉我您在这方面遵循的任何经验法则或约定。
回答by Brian R. Bondy
Unless you are forced to use C, you should never usemalloc
. Always use new
.
除非你被迫使用 C,否则你永远不应该使用malloc
. 始终使用new
.
If you need a big chunk of data just do something like:
如果您需要大量数据,只需执行以下操作:
char *pBuffer = new char[1024];
Be careful though this is not correct:
尽管这是不正确的,但要小心:
//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;
Instead you should do this when deleting an array of data:
相反,您应该在删除数据数组时执行此操作:
//This deletes all items in the array
delete[] pBuffer;
The new
keyword is the C++ way of doing it, and it will ensure that your type will have its constructor called. The new
keyword is also more type-safewhereas malloc
is not type-safe at all.
该new
关键字是做它的C ++的方式,这将确保你的类型都会有所谓的构造。该new
关键字也更加类型安全,而malloc
根本不是类型安全的。
The only way I could think that would be beneficial to use malloc
would be if you needed to change the size of your bufferof data. The new
keyword does not have an analogous way like realloc
. The realloc
function might be able to extend the size of a chunk of memory for you more efficiently.
我认为这对使用有益的唯一方法malloc
是,如果您需要更改数据缓冲区的大小。该new
关键字没有像类似的方式realloc
。该realloc
函数可能能够更有效地为您扩展一块内存的大小。
It is worth mentioning that you cannot mix new
/free
and malloc
/delete
.
值得一提的是,您不能混合使用new
/free
和malloc
/ delete
。
Note: Some answers in this question are invalid.
注意:此问题中的某些答案无效。
int* p_scalar = new int(5); // Does not create 5 elements, but initializes to 5
int* p_array = new int[5]; // Creates 5 elements
回答by Flexo
The short answer is: don't use malloc
for C++ without a really good reason for doing so. malloc
has a number of deficiencies when used with C++, which new
was defined to overcome.
简短的回答是:不要在没有malloc
充分理由的情况下使用C++。malloc
与 C++ 一起使用时有许多缺陷,这些缺陷new
被定义为要克服。
Deficiencies fixed by new for C++ code
由 new 为 C++ 代码修复的缺陷
malloc
is not typesafe in any meaningful way. In C++ you are required to cast the return fromvoid*
. This potentially introduces a lot of problems:#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 }
It's worse than that though. If the type in question is POD (plain old data)then you can semi-sensibly use
malloc
to allocate memory for it, asf2
does in the first example.It's not so obvious though if a type is POD. The fact that it's possible for a given type to change from POD to non-POD with no resulting compiler error and potentially very hard to debug problems is a significant factor. For example if someone (possibly another programmer, during maintenance, much later on were to make a change that caused
foo
to no longer be POD then no obvious error would appear at compile time as you'd hope, e.g.:struct foo { double d[5]; virtual ~foo() { } };
would make the
malloc
off2
also become bad, without any obvious diagnostics. The example here is trivial, but it's possible to accidentally introduce non-PODness much further away (e.g. in a base class, by adding a non-POD member). If you have C++11/boost you can useis_pod
to check that this assumption is correct and produce an error if it's not:#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))); }
Although boost is unable to determine if a type is PODwithout C++11 or some other compiler extensions.
malloc
returnsNULL
if allocation fails.new
will throwstd::bad_alloc
. The behaviour of later using aNULL
pointer is undefined. An exception has clean semantics when it is thrown and it is thrown from the source of the error. Wrappingmalloc
with an appropriate test at every call seems tedious and error prone. (You only have to forget once to undo all that good work). An exception can be allowed to propagate to a level where a caller is able to sensibly process it, where asNULL
is much harder to pass back meaningfully. We could extend oursafe_foo_malloc
function to throw an exception or exit the program or call some handler:#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; }
Fundamentally
malloc
is a C feature andnew
is a C++ feature. As a resultmalloc
does not play nicely with constructors, it only looks at allocating a chunk of bytes. We could extend oursafe_foo_malloc
further to use placementnew
:#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(); }
Our
safe_foo_malloc
function isn't very generic - ideally we'd want something that can handle any type, not justfoo
. We can achieve this with templates and variadic templates for non-default constructors:#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)...); } };
Now though in fixing all the issues we identified so far we've practically reinvented the default
new
operator. If you're going to usemalloc
and placementnew
then you might as well just usenew
to begin with!
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 }
然而,情况比这更糟糕。如果有问题的类型是POD(纯旧数据),那么您可以半明智地使用
malloc
它为它分配内存,就像f2
在第一个示例中一样。如果类型是 POD,则不是那么明显。给定类型可能从 POD 更改为非 POD 而不会导致编译器错误并且可能很难调试问题这一事实是一个重要因素。例如,如果有人(可能是另一位程序员,在维护期间,稍后进行更改导致
foo
不再是 POD,那么在编译时不会出现您希望的明显错误,例如:struct foo { double d[5]; virtual ~foo() { } };
将使
malloc
中f2
也变得不好,没有任何明显的诊断。这里的例子很简单,但可能会意外地在更远的地方引入非 POD 性(例如,在基类中,通过添加非 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))); }
尽管 boost无法在没有 C++11 或其他一些编译器扩展的情况下确定类型是否为 POD。
malloc
NULL
如果分配失败则返回。new
会扔std::bad_alloc
。稍后使用NULL
指针的行为是未定义的。异常在抛出时具有清晰的语义,并且是从错误源抛出的。包装malloc
与每次调用适当的测试似乎有些单调乏味,而且容易出错。(您只需忘记一次即可撤消所有出色的工作)。可以允许异常传播到调用者能够明智地处理它的级别,而在该级别上NULL
更难以有意义地传回。我们可以扩展我们的safe_foo_malloc
函数以抛出异常或退出程序或调用一些处理程序:#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
函数不是很通用——理想情况下,我们想要一些可以处理任何类型的东西,而不仅仅是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)...); } };
现在虽然在解决我们迄今为止发现的所有问题时,我们实际上已经重新发明了默认
new
运算符。如果您要使用malloc
和放置,new
那么您不妨new
从一开始就使用!
回答by Matthias Benkard
From the C++ FQA Lite:
来自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.
[16.4] 为什么我应该使用 new 而不是值得信赖的 old malloc()?
FAQ:new/delete调用构造函数/析构函数;new 是类型安全的,malloc 不是;new 可以被一个类覆盖。
FQA:FAQ中提到的new的优点不是优点,因为构造函数、析构函数和运算符重载都是垃圾(看看没有垃圾收集会发生什么?),类型安全问题在这里真的很小(通常你有将 malloc 返回的 void* 转换为正确的指针类型以将其分配给类型化的指针变量,这可能很烦人,但远非“不安全”)。
哦,使用值得信赖的旧 malloc 可以使用同样值得信赖和旧的 realloc。太糟糕了,我们没有闪亮的新运营商更新或其他东西。
尽管如此,即使语言是 C++,new 也不足以证明偏离整个语言使用的通用风格是合理的。特别是,如果您简单地 malloc 对象,具有非平凡构造函数的类将以致命的方式行为不端。那么为什么不在整个代码中使用 new 呢?人们很少重载 operator new,因此它可能不会过多地妨碍您。如果他们确实超载新的,您可以随时要求他们停止。
Sorry, I just couldn't resist. :)
对不起,我实在是忍不住了。:)
回答by Ferruccio
Always use new in C++. If you need a block of untyped memory, you can use operator new directly:
在 C++ 中始终使用 new。如果需要一块无类型内存,可以直接使用operator new:
void *p = operator new(size);
...
operator delete(p);
回答by dmckee --- ex-moderator kitten
Use malloc
and free
onlyfor allocating memory that is going to be managed by c-centric libraries and APIs. Use new
and delete
(and the []
variants) for everything that you control.
使用malloc
并只用于分配要由C-中心库和API来管理内存。对您控制的所有内容使用and (和变体)。free
new
delete
[]
回答by Yogeesh H T
new vs malloc()
new vs malloc()
1) new
is an operator, while malloc()
is a function.
1)new
是一个运算符,而malloc()
是一个函数。
2) new
calls constructors, while malloc()
does not.
2)new
调用构造函数,而malloc()
不会。
3) new
returns exact data type, while malloc()
returns void *.
3)new
返回精确数据类型,而malloc()
返回void *。
4) new
never returns a NULL(will throw on failure) while malloc()
returns NULL
4)new
从不返回NULL(失败时会抛出)而malloc()
返回 NULL
5) Reallocation of memory not handled by new
while malloc()
can
5) 未由new
while处理的内存重新分配malloc()
可以
回答by The Quantum Physicist
To answer your question, you should know the difference between malloc
and new
. The difference is simple:
要回答你的问题,你应该知道的区别malloc
和new
。区别很简单:
malloc
allocates memory, while new
allocates memory AND calls the constructorof the object you're allocating memory for.
malloc
分配内存,同时new
分配内存并调用您为其分配内存的对象的构造函数。
So, unless you're restricted to C, you should never use malloc, especially when dealing with C++ objects. That would be a recipe for breaking your program.
因此,除非您仅限于使用 C,否则永远不应使用 malloc,尤其是在处理 C++ 对象时。那将是破坏程序的秘诀。
Also the difference between free
and delete
is quite the same. The difference is that delete
will call the destructor of your object in addition to freeing memory.
free
和之间的区别也delete
完全相同。不同之处在于delete
,除了释放内存之外,还会调用对象的析构函数。
回答by R. Martinho Fernandes
There is one big difference between malloc
and new
. malloc
allocates memory. This is fine for C, because in C, a lump of memory is an object.
malloc
和之间有一个很大的区别new
。malloc
分配内存。这对 C 来说很好,因为在 C 中,一块内存是一个对象。
In C++, if you're not dealing with POD types (which are similar to C types) you must call a constructor on a memory location to actually have an object there. Non-POD types are very common in C++, as many C++ features make an object automatically non-POD.
在 C++ 中,如果您不处理 POD 类型(类似于 C 类型),您必须在内存位置调用构造函数才能在那里实际拥有一个对象。非 POD 类型在 C++ 中非常常见,因为许多 C++ 特性使对象自动成为非 POD。
new
allocates memory andcreates an object on that memory location. For non-POD types this means calling a constructor.
new
分配内存并在该内存位置创建一个对象。对于非 POD 类型,这意味着调用构造函数。
If you do something like this:
如果你做这样的事情:
non_pod_type* p = (non_pod_type*) malloc(sizeof *p);
The pointer you obtain cannot be dereferenced because it does not point to an object. You'd need to call a constructor on it before you can use it (and this is done using placement new
).
您获得的指针不能取消引用,因为它不指向对象。在使用它之前,您需要对其调用构造函数(这是使用 position 完成的new
)。
If, on the other hand, you do:
另一方面,如果你这样做:
non_pod_type* p = new non_pod_type();
You get a pointer that is always valid, because new
created an object.
你得到一个始终有效的指针,因为new
创建了一个对象。
Even for POD types, there's a significant difference between the two:
即使对于 POD 类型,两者之间也存在显着差异:
pod_type* p = (pod_type*) malloc(sizeof *p);
std::cout << p->foo;
This piece of code would print an unspecified value, because the POD objects created by malloc
are not initialised.
这段代码会打印一个未指定的值,因为创建的 POD 对象malloc
没有初始化。
With new
, you could specify a constructor to call, and thus get a well defined value.
使用new
,您可以指定要调用的构造函数,从而获得定义明确的值。
pod_type* p = new pod_type();
std::cout << p->foo; // prints 0
If you really want it, you can use use new
to obtain uninitialised POD objects. See this other answerfor more information on that.
如果你真的想要它,你可以使用 usenew
来获取未初始化的 POD 对象。有关更多信息,请参阅此其他答案。
Another difference is the behaviour upon failure. When it fails to allocate memory, malloc
returns a null pointer, while new
throws an exception.
另一个区别是失败时的行为。当分配内存失败时,malloc
返回空指针,同时new
抛出异常。
The former requires you to test every pointer returned before using it, while the later will always produce valid pointers.
前者要求您在使用之前测试返回的每个指针,而后者将始终产生有效的指针。
For these reasons, in C++ code you should use new
, and not malloc
. But even then, you should not use new
"in the open", because it acquires resources you need to release later on. When you use new
you should pass its result immediately into a resource managing class:
由于这些原因,在 C++ 代码中你应该使用new
,而不是malloc
。但即便如此,您也不应该使用new
“in the open”,因为它会获取您稍后需要释放的资源。当您使用时,new
您应该立即将其结果传递给资源管理类:
std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak
回答by JVApen
Dynamic allocation is only required when the life-time of the object should be different than the scope it gets created in (This holds as well for making the scope smaller as larger) and you have a specific reason where storing it by value doesn't work.
仅当对象的生命周期与其创建的作用域不同时才需要动态分配(这对于使作用域变大变小也成立)并且您有一个特定的原因不按值存储它工作。
For example:
例如:
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);
From C++11 on, we have std::unique_ptr
for dealing with allocated memory, which contains the ownership of the allocated memory. std::shared_ptr
was created for when you have to share ownership. (you'll need this less than you would expect in a good program)
从 C++11 开始,我们必须std::unique_ptr
处理分配的内存,其中包含已分配内存的所有权。std::shared_ptr
是为您必须共享所有权而创建的。(在一个好的程序中,你需要的比你期望的要少)
Creating an instance becomes really easy:
创建实例变得非常简单:
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
C++17 also adds std::optional
which can prevent you from requiring memory allocations
C++17 还添加了std::optional
可以防止您需要内存分配的功能
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
As soon as 'instance' goes out of scope, the memory gets cleaned up. Transferring ownership is also easy:
一旦“实例”超出范围,内存就会被清理。转让所有权也很容易:
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)
So when do you still need new
? Almost never from C++11 on. Most of the you use std::make_unique
until you get to a point where you hit an API that transfers ownership via raw pointers.
那你new
什么时候还需要?从 C++11 开始几乎没有。您使用的大部分内容,std::make_unique
直到您到达通过原始指针传输所有权的 API 为止。
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
In C++98/03, you have to do manual memory management. If you are in this case, try upgrading to a more recent version of the standard. If you are stuck:
在 C++98/03 中,您必须进行手动内存管理。如果您遇到这种情况,请尝试升级到更新版本的标准。如果你卡住了:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Make sure that you track the ownership correctly to not have any memory leaks! Move semantics don't work yet either.
确保您正确跟踪所有权,以免出现任何内存泄漏!移动语义也不起作用。
So, when do we need malloc in C++? The only valid reason would be to allocate memory and initialize it later via placement new.
那么,我们什么时候需要在 C++ 中使用 malloc 呢?唯一有效的原因是分配内存并稍后通过placement new 对其进行初始化。
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
Even though, the above is valid, this can be done via a new-operator as well. std::vector
is a good example for this.
尽管上述内容是有效的,但这也可以通过 new-operator 来完成。std::vector
是一个很好的例子。
Finally, we still have the elephant in the room: C
. If you have to work with a C-library where memory gets allocated in the C++ code and freed in the C code (or the other way around), you are forced to use malloc/free.
最后,我们仍然有大象在房间里:C
。如果您必须使用 C 库,其中内存在 C++ 代码中分配并在 C 代码中释放(或其他方式),您将被迫使用 malloc/free。
If you are in this case, forget about virtual functions, member functions, classes ... Only structs with PODs in it are allowed.
如果你在这种情况下,忘记虚函数、成员函数、类......只允许包含 POD 的结构。
Some exceptions to the rules:
规则的一些例外情况:
- You are writing a standard library with advanced data structures where malloc is appropriate
- You have to allocate big amounts of memory (In memory copy of a 10GB file?)
- You have tooling preventing you to use certain constructs
- You need to store an incomplete type
- 您正在编写一个具有高级数据结构的标准库,其中 malloc 是合适的
- 您必须分配大量内存(10GB 文件的内存副本?)
- 你有工具阻止你使用某些结构
- 您需要存储不完整的类型
回答by herohuyongtao
There are a few things which new
does that malloc
doesn't:
有一些事情new
不malloc
会这样做:
new
constructs the object by calling the constructor of that objectnew
doesn't require typecasting of allocated memory.- It doesn't require an amount of memory to be allocated, rather it requires a number of objects to be constructed.
new
通过调用该对象的构造函数来构造该对象new
不需要对分配的内存进行类型转换。- 它不需要分配大量内存,而是需要构造多个对象。
So, if you use malloc
, then you need to do above things explicitly, which is not always practical. Additionally, new
can be overloaded but malloc
can't be.
所以,如果你使用malloc
,那么你需要明确地做上面的事情,这并不总是实用的。此外,new
可以重载但malloc
不能重载。