What is Dynamic Memory Allocation in C++?
I'm learning about Dynamic Memory Allocation in C++ and the keywords new
and new[]
are mentioned. It is said to enable users to specify the size of the memory allocation at runtime, unlike simply declaring a variable or array with a fixed size in the source code.
I don't understand this concept. How does it work? I just need a clarification on the idea and an example would be helpful!
So, if you want an array of 10 integers, you'd be writing:
int arr[10];
But what if you wanted to do something like this;
cout << "How many?";
cin >> num;
int arr[num];
Well, the C++ language doesn't allow that. Instead, you have to do:
int *arr = new int[num];
to create your array. And later on you MUST[1] use:
delete [] arr;
to free the memory.
So, how does this work? When you call new, the C++ runtime library [the code that you didn't have to write that makes up the fundamentals of C++] will figure out how much space num
integers take up, and find some space in memory for that. I'm not going into details of "how you find some memory". For now, just trust me, there is some memory available somewhere that can be used to store some integers in.
When you later call delete
, that same memory is given back to the "pool" or "heap" of memory that it came from.
Of course, if you have a machine with, say, 256 MB of memory, and you try to ask for space to store 250 million integers, bearing in mind that an integer takes up more than one byte, it's not going to work out - there is no "magic" here - the memory is still limited to how much is available in the machine.... You just have the right to determine in the program, when it's running, how much memory you need, rather than having to decide when WRITING the program.
Edit: It is generally best to "hide" any memory allocation using the already existing "container-" and "wrapper-classes" that are useful for this very purpose. For example:
std::vector<int> arr;
would work as a variable storage for integers, and you never have to worry about freeing the memory, or even knowing how many you need before you have stored them there.
std::shared_ptr<int> arr = new int[num];
is another case, where when the "shared_ptr" is no longer in use [it track that inside the shared pointer class, so you never need to care about freeing the memory].
[1] If you don't want to leak memory, and it's "bad style" to leak memory. Not making anyone happy if you do.
I've seen many posts about memory allocation in C++, questions about "new operator" vs "operator new", questions about new int(100)
vs new int[100]
, questions about memory initialization... I think there should be an answer that summarizes everything clearly once and for all, and I'm choosing this question to write this summary. It is about dynamic memory allocation, ie allocations on the heap at runtime. I also provide a summary implementation (public domain).
C vs C++
Main functions for dynamic memory allocations:
<cstdlib>
), we have mainly malloc
and calloc
and free
. I won't talk about realloc
. <new>
), we have: new T( args )
new (std::nothrow) T( args )
delete ( T* )
new T[ size_t ]
new (std::nothrow) T[ size_t ]
delete[] ( T* )
new (void*) T( args )
new (void*) T[ size_t ]
::operator new( size_t )
; ::operator new( size_t, std::nothrow )
; ::operator new( size_t, ptr )
. Please look at this post for a concise comparison.
Legacy C dynamic allocations
Main points : complete type-erasure ( void*
pointers), and therefore no construction/destruction , size specified in bytes (typically using sizeof
).
malloc( size_t )
does not initialize memory at all (raw memory contains garbage, always initialize manually before use). calloc( size_t, size_t )
initializes all bits to 0 (slight overhead, but useful for POD numeric types). Any allocated memory should be released using free
ONLY .
Construction/destruction of class instances should be done manually before use / before memory release.
C++ dynamic allocations
Main points : confusing because of similar syntaxes doing different things, all delete
-statements call the destructor, all delete
-statements take fully typed pointers, some new
-statements return fully-typed pointers, some new
-statements call some constructor.
Warning : as you will see below, new
can either be a keyword OR function. It is best not to talk about "new operator" and/or "operator new" in order to avoid confusions. I call " new
-statements" any valid statements that contain new
either as a function or keyword. People also talk about " new
-expressions", where new
is the keyword and not the function.
Raw memory allocation (no initialization)
Do not use this yourself. This is used internally by new-expressions (see below).
::operator new( size_t )
and ::operator new( size_t, std::nothrow )
take a size in bytes, and return a void*
in case of success. std::bad_alloc
, the latter returns NULL
. ::operator new( sizeof(T) )
for a single object of type T
(and delete
for release), and ::operator new( n*sizeof(T) )
for multiple objects (and delete[]
for release). These allocations do not initialize memory, and in particular, they do not call the default-constructor on the allocated objects. Therefore you MUST initialize ALL the elements manually before you release the allocation using either delete
or delete[]
.
Note : I couldn't stress enough that you should NOT use this yourself. If you should use it, however, make sure you pass a pointer to void
instead of a typed pointer when calling either delete
or delete[]
on such allocations (always after initializing manually). I have personally experienced runtime errors with non-POD types with some compilers (maybe my mistake).
Raw memory initialization (no allocation)
Do not use this yourself. This is used internally by new-expressions (see below). In the following, I assume void *ptr = ::operator new( n*sizeof(T) )
for some type T
and size n
.
Then ::operator new( n*sizeof(T), (T*) ptr )
initializes n
elements of type T
starting from ptr
using the default constructor T::T()
. There is no allocation here, only initialization using the default-constructor.
Single-object allocation & initialization
new T( args )
allocates and initializes memory for a single object of type T
using the constructor T::T( args )
. The default constructor will not be called unless arguments are omitted (ie new T()
or even new T
). Throws an exception std::bad_alloc
on failure. new (std::nothrow) T( args )
except that it returns NULL
in case of failure. delete
to call the destructor T::~T()
and release the corresponding memory. Multiple-objects allocation & initialization
new T[n]
allocates and initializes memory for a n
objects of type T
using the default constructor. Throws an exception std::bad_alloc
on failure. new (std::nothrow) T[n]
except that it returns NULL
in case of failure. delete[]
to call the destructor T::~T()
for each element and release the corresponding memory. Memory initialization (aka "placement new")
No allocation here. Regardless of how the allocation was made:
new (ptr) T(args)
calls the constructor T::T(args)
on the memory stored at ptr
. The default constructor is not called unless arguments are omitted. new (ptr) T[n]
calls the default constructor T::T()
on n
objects of type T
stored from ptr
to ptr+n
(ie, n*sizeof(T)
bytes). Related posts
上一篇: 私人,公共和受保护继承的区别
下一篇: 什么是C ++中的动态内存分配?