The need for dynamic memory allocation
C++ supports three basic types of memory allocation, of which you’ve already seen two.
- Static memory allocation happens for static and global variables. Memory for these types of variables is allocated once when your program is run and persists throughout the life of your program.
- Automatic memory allocation happens for function parameters and local variables. Memory for these types of variables is allocated when the relevant block is entered, and freed when the block is exited, as many times as necessary.
- Dynamic memory allocation is the topic of this article.
Both static and automatic allocation have two things in common:
- The size of the variable / array must be known at compile time.
- Memory allocation and deallocation happens automatically (when the variable is instantiated / destroyed).
Most of the time, this is just fine. However, you will come across situations where one or both of these constraints cause problems, usually when dealing with external (user or file) input.
For example, we may want to use a string to hold someone’s name, but we do not know how long their name is until they enter it. Or we may want to read in a number of records from disk, but we don’t know in advance how many records there are. Or we may be creating a game, with a variable number of monsters (that changes over time as some monsters die and new ones are spawned) trying to kill the player.
If we have to declare the size of everything at compile time, the best we can do is try to make a guess the maximum size of variables we’ll need and hope that’s enough:
1 2 3 4 |
char name[25]; // let's hope their name is less than 25 chars! Record record[500]; // let's hope there are less than 500 records! Monster monster[40]; // 40 monsters maximum Polygon rendering[30000]; // this 3d rendering better not have more than 30,000 polygons! |
This is a poor solution for at least four reasons:
First, it leads to wasted memory if the variables aren’t actually used. For example, if we allocate 25 chars for every name, but names on average are only 12 chars long, we’re using over twice what we really need. Or consider the rendering array above: if a rendering only uses 10,000 polygons, we have 20,000 Polygons worth of memory not being used!
Second, how do we tell which bits of memory are actually used? For strings, it’s easy: a string that starts with a \0 is clearly not being used. But what about monster[24]? Is it alive or dead right now? That necessitates having some way to tell active from inactive items, which adds complexity and can use up additional memory.
Third, most normal variables (including fixed arrays) are allocated in a portion of memory called the stack. The amount of stack memory for a program is generally quite small -- Visual Studio defaults the stack size to 1MB. If you exceed this number, stack overflow will result, and the operating system will probably close down the program.
On Visual Studio, you can see this happen when running this program:
1 2 3 4 |
int main() { int array[1000000]; // allocate 1 million integers (probably 4MB of memory) } |
Being limited to just 1MB of memory would be problematic for many programs, especially those that deal with graphics.
Fourth, and most importantly, it can lead to artificial limitations and/or array overflows. What happens when the user tries to read in 600 records from disk, but we’ve only allocated memory for a maximum of 500 records? Either we have to give the user an error, only read the 500 records, or (in the worst case where we don’t handle this case at all) overflow the record array and watch something bad happen.
Fortunately, these problems are easily addressed via dynamic memory allocation. Dynamic memory allocation is a way for running programs to request memory from the operating system when needed. This memory does not come from the program’s limited stack memory -- instead, it is allocated from a much larger pool of memory managed by the operating system called the heap. On modern machines, the heap can be gigabytes in size.
Dynamically allocating single variables
To allocate a single variable dynamically, we use the scalar (non-array) form of the new operator:
1 |
new int; // dynamically allocate an integer (and discard the result) |
In the above case, we’re requesting an integer’s worth of memory from the operating system. The new operator creates the object using that memory, and then returns a pointer containing the address of the memory that has been allocated.
Most often, we’ll assign the return value to our own pointer variable so we can access the allocated memory later.
1 |
int *ptr{ new int }; // dynamically allocate an integer and assign the address to ptr so we can access it later |
We can then perform indirection through the pointer to access the memory:
1 |
*ptr = 7; // assign value of 7 to allocated memory |
If it wasn’t before, it should now be clear at least one case in which pointers are useful. Without a pointer to hold the address of the memory that was just allocated, we’d have no way to access the memory that was just allocated for us!
How does dynamic memory allocation work?
Your computer has memory (probably lots of it) that is available for applications to use. When you run an application, your operating system loads the application into some of that memory. This memory used by your application is divided into different areas, each of which serves a different purpose. One area contains your code. Another area is used for normal operations (keeping track of which functions were called, creating and destroying global and local variables, etc…). We’ll talk more about those later. However, much of the memory available just sits there, waiting to be handed out to programs that request it.
When you dynamically allocate memory, you’re asking the operating system to reserve some of that memory for your program’s use. If it can fulfill this request, it will return the address of that memory to your application. From that point forward, your application can use this memory as it wishes. When your application is done with the memory, it can return the memory back to the operating system to be given to another program.
Unlike static or automatic memory, the program itself is responsible for requesting and disposing of dynamically allocated memory.
Initializing a dynamically allocated variable
When you dynamically allocate a variable, you can also initialize it via direct initialization or uniform initialization (in C++11):
1 2 |
int *ptr1{ new int (5) }; // use direct initialization int *ptr2{ new int { 6 } }; // use uniform initialization |
Deleting single variables
When we are done with a dynamically allocated variable, we need to explicitly tell C++ to free the memory for reuse. For single variables, this is done via the scalar (non-array) form of the delete operator:
1 2 3 |
// assume ptr has previously been allocated with operator new delete ptr; // return the memory pointed to by ptr to the operating system ptr = 0; // set ptr to be a null pointer (use nullptr instead of 0 in C++11) |
What does it mean to delete memory?
The delete operator does not actually delete anything. It simply returns the memory being pointed to back to the operating system. The operating system is then free to reassign that memory to another application (or to this application again later).
Although it looks like we’re deleting a variable, this is not the case! The pointer variable still has the same scope as before, and can be assigned a new value just like any other variable.
Note that deleting a pointer that is not pointing to dynamically allocated memory may cause bad things to happen.
Dangling pointers
C++ does not make any guarantees about what will happen to the contents of deallocated memory, or to the value of the pointer being deleted. In most cases, the memory returned to the operating system will contain the same values it had before it was returned, and the pointer will be left pointing to the now deallocated memory.
A pointer that is pointing to deallocated memory is called a dangling pointer. Indirection through- or deleting a dangling pointer will lead to undefined behavior. Consider the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int *ptr{ new int }; // dynamically allocate an integer *ptr = 7; // put a value in that memory location delete ptr; // return the memory to the operating system. ptr is now a dangling pointer. std::cout << *ptr; // Indirection through a dangling pointer will cause undefined behavior delete ptr; // trying to deallocate the memory again will also lead to undefined behavior. return 0; } |
In the above program, the value of 7 that was previously assigned to the allocated memory will probably still be there, but it’s possible that the value at that memory address could have changed. It’s also possible the memory could be allocated to another application (or for the operating system’s own usage), and trying to access that memory will cause the operating system to shut the program down.
Deallocating memory may create multiple dangling pointers. Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { int *ptr{ new int{} }; // dynamically allocate an integer int *otherPtr{ ptr }; // otherPtr is now pointed at that same memory location delete ptr; // return the memory to the operating system. ptr and otherPtr are now dangling pointers. ptr = nullptr; // ptr is now a nullptr // however, otherPtr is still a dangling pointer! return 0; } |
There are a few best practices that can help here.
First, try to avoid having multiple pointers point at the same piece of dynamic memory. If this is not possible, be clear about which pointer “owns” the memory (and is responsible for deleting it) and which are just accessing it.
Second, when you delete a pointer, if that pointer is not going out of scope immediately afterward, set the pointer to 0 (or nullptr in C++11). We’ll talk more about null pointers, and why they are useful in a bit.
Rule
Set deleted pointers to 0 (or nullptr in C++11) unless they are going out of scope immediately afterward.
Operator new can fail
When requesting memory from the operating system, in rare circumstances, the operating system may not have any memory to grant the request with.
By default, if new fails, a bad_alloc exception is thrown. If this exception isn’t properly handled (and it won’t be, since we haven’t covered exceptions or exception handling yet), the program will simply terminate (crash) with an unhandled exception error.
In many cases, having new throw an exception (or having your program crash) is undesirable, so there’s an alternate form of new that can be used instead to tell new to return a null pointer if memory can’t be allocated. This is done by adding the constant std::nothrow between the new keyword and the allocation type:
1 |
int *value = new (std::nothrow) int; // value will be set to a null pointer if the integer allocation fails |
In the above example, if new fails to allocate memory, it will return a null pointer instead of the address of the allocated memory.
Note that if you then attempt indirection through this pointer, undefined behavior will result (most likely, your program will crash). Consequently, the best practice is to check all memory requests to ensure they actually succeeded before using the allocated memory.
1 2 3 4 5 6 |
int *value{ new (std::nothrow) int{} }; // ask for an integer's worth of memory if (!value) // handle case where new returned null { // Do error handling here std::cout << "Could not allocate memory"; } |
Because asking new for memory only fails rarely (and almost never in a dev environment), it’s common to forget to do this check!
Null pointers and dynamic memory allocation
Null pointers (pointers set to address 0 or nullptr) are particularly useful when dealing with dynamic memory allocation. In the context of dynamic memory allocation, a null pointer basically says “no memory has been allocated to this pointer”. This allows us to do things like conditionally allocate memory:
1 2 3 |
// If ptr isn't already allocated, allocate it if (!ptr) ptr = new int; |
Deleting a null pointer has no effect. Thus, there is no need for the following:
1 2 |
if (ptr) delete ptr; |
Instead, you can just write:
1 |
delete ptr; |
If ptr is non-null, the dynamically allocated variable will be deleted. If it is null, nothing will happen.
Memory leaks
Dynamically allocated memory stays allocated until it is explicitly deallocated or until the program ends (and the operating system cleans it up, assuming your operating system does that). However, the pointers used to hold dynamically allocated memory addresses follow the normal scoping rules for local variables. This mismatch can create interesting problems.
Consider the following function:
1 2 3 4 |
void doSomething() { int *ptr{ new int{} }; } |
This function allocates an integer dynamically, but never frees it using delete. Because pointers variables are just normal variables, when the function ends, ptr will go out of scope. And because ptr is the only variable holding the address of the dynamically allocated integer, when ptr is destroyed there are no more references to the dynamically allocated memory. This means the program has now “lost” the address of the dynamically allocated memory. As a result, this dynamically allocated integer can not be deleted.
This is called a memory leak. Memory leaks happen when your program loses the address of some bit of dynamically allocated memory before giving it back to the operating system. When this happens, your program can’t delete the dynamically allocated memory, because it no longer knows where it is. The operating system also can’t use this memory, because that memory is considered to be still in use by your program.
Memory leaks eat up free memory while the program is running, making less memory available not only to this program, but to other programs as well. Programs with severe memory leak problems can eat all the available memory, causing the entire machine to run slowly or even crash. Only after your program terminates is the operating system able to clean up and “reclaim” all leaked memory.
Although memory leaks can result from a pointer going out of scope, there are other ways that memory leaks can result. For example, a memory leak can occur if a pointer holding the address of the dynamically allocated memory is assigned another value:
1 2 3 |
int value = 5; int *ptr{ new int{} }; // allocate memory ptr = &value; // old address lost, memory leak results |
This can be fixed by deleting the pointer before reassigning it:
1 2 3 4 |
int value{ 5 }; int *ptr{ new int{} }; // allocate memory delete ptr; // return memory back to operating system ptr = &value; // reassign pointer to address of value |
Relatedly, it is also possible to get a memory leak via double-allocation:
1 2 |
int *ptr{ new int{} }; ptr = new int{}; // old address lost, memory leak results |
The address returned from the second allocation overwrites the address of the first allocation. Consequently, the first allocation becomes a memory leak!
Similarly, this can be avoided by ensuring you delete the pointer before reassigning.
Conclusion
Operators new and delete allow us to dynamically allocate single variables for our programs.
Dynamically allocated memory has dynamic duration and will stay allocated until you deallocate it or the program terminates.
Be careful not to perform indirection through dangling or null pointers.
In the next lesson, we’ll take a look at using new and delete to allocate and delete arrays.
![]() |
![]() |
![]() |
What is the point in new when we could use vectors which allow the same thing but seem to be more closely related to arrays?
If your goal is to dynamically allocate an array, then you should generally favor std::vector over new. It's much safer.
However, new isn't limited to allocating arrays -- you can dynamically allocate scalar (non-array) values too. If you want to dynamically allocate a scalar, std::vector isn't appropriate at all.
Thanks for clarifying
Just to clarify something :)
we should delete the (*ptr), before it goes out of the scope? That is good practice, to free memory.
Yes, that's what the paragraph is about. Not deleting @ptr results in a memory leak.
Hi,
How much (precisely) memory does the heap contain?
Can the heap overflow?
Can we modify the memory that new allocates?
Will the new operator ever obtain arbitrary memory?
Hi Haider!
> How much (precisely) memory does the heap contain?
32 bit machines can address 2^32 bytes = 4GiB
64 bit machines can address 2^64 bytes = 16EiB (That's 16777216TiB)
Since you don't have 16EiB of memory, your memory + swap is the limit.
> Can the heap overflow?
There's nowhere it could overflow to. Once it's full it's full. You have to handle this case in your program. In practice this is rarely done, because the heap is large enough.
> Can we modify the memory that new allocates?
> Will the new operator ever obtain arbitrary memory?
Not sure what you mean. @new will take memory from wherever it's available without removing old content. If you're handling sensitive data (eg. passwords) in your program, you should manually clear the memory once you don't need it anymore.
Thanks.
Hi Alex,
Does the C++ standard say that dynamically allocating memory using 'new' also initializes the allocated memory location with zeroes?
I'm coming from a C background. Every time I do a malloc(), I should explicitly zero out the allocated memory to clear out the garbage. Does 'new' do that for me automatically? My toy programs on C++17 seem to be doing that, but not sure if that is the standard behavior.
Thanks,
Nitin
Hi Nitin!
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int* ptr = new int ;
*ptr = 2;
cout <<&ptr << "\n";//prints 00DDFDA8
cout << ptr << "\n";//prints 01258310
cout << *ptr << "\n";//prints 2
cout << new int << "\n";//prints 01254590
// why isn't ptr equal to new int ??
return 0;
}
@new allocates new memory every time you call it and returns the address of the allocated memory.
(new int) is a pointer that points to the dynamically allocated memory and int* ptr=new int; so (ptr) is supposed to have the same address as (new int) I think
@new isn't one value, it's a function
isn't (ptr) supposed to be equal to ( new int ) as value of (new int) which is an address is assigned to (ptr)?? so why when it prints (ptr) is different from when it prints (new int) ?? isn't it supposed to print the same address?? I know that new allocates new memory every time but as this new allocated memory every time is supposed to be assigned to ptr so when it prints (ptr) and (new int) they must have the same address??
> isn't (ptr) supposed to be equal to ( new int )
The first time you call it, yes. But you call it again, creating more memory, which can't be the same memory as before, because it's new memory.
You're creating new memory, storing the address in @ptr. You're then creating new memory again, and just printing the address.
When I call @new again the addresses that both @new and @ptr hold change , which one of the new addresses holds the value of the number 2 ? the new address of @new or the new address of @ptr ?? because both addresses of @new and @ptr are now different , so which of both addresses should I trust to still hold the value of number 2 after changing ??
And is anyone of them pointing to some garbage address after changing ?? And if , which one of them ??
@new doesn't hold a value, it's a function.
The address @ptr is holding isn't affected by another call to @new, you're doing something wrong, code please.
The code is the same as the above
Your code above doesn't have a variable called "new"
Regarding:
"Initializing a dynamically allocated variable
When you dynamically allocate a variable, you can also initialize it via direct initialization or uniform initialization (in C++11):
"
What about this:
It seems to work and uses uniform initialization throughout. Is there a reason not to do it this way?
I've never seen anybody do this, but I can't find a reason why not, so I can only suppose people don't like the nesting. Personally, I find it harder to read than int *ptr2 = new int {6};
Hello,
In the part "Initializing a dynamically allocated variable", I got surprised than there is Direct and Uniforme initialization but no copy initialization like for variable. There is any explanation about it ? (I remembre uniforme and direct are best over copy, I am only curious)
Also when i try
in visual studio, I got 2 error:
"'=': cannot convert from 'int' to 'int *"
"expression must be a modifiable lvalue"
For the first one i guess this mean They have not define an '=' operator for new but i am not sure about the meaning .
The seconde one is kind of the same ? We can't assign a literal value directly to a pointer ?
There is no copy initialization for dynamic variables because the syntax would be rather confusing (as it would use the equals sign twice).
You can't assign a literal value directly to a pointer because pointers hold memory addresses as values. The only exception is for literal 0, to denote a null pointer.
so why fixed arrays should have their length at compile time?? . I didn't understand why till now , i need a good explanation.
I read on other forums that it should get the length at compile time to calculate the size of the Stack but i didn't understand also !
When variables are defined (either locally or as function parameters), the compiler will lay them out as part of the stack frames. To do this, it needs to know how big those variables are. An array without a fixed size would violate this.
Dynamic memory works because the pointers have a fixed size, so the compiler can lay out where the pointer will go in memory ahead of time.
For more info on stack frames, see lesson 7.9.
Hello,
You wrote that for static and automatic allocation,
"The size of the variable / array must be known at compile time".
I wrote a program in c++ and I wanted to know if this is a violation/exception of the rule stated above.
Hi Baljinder!
That way of creating an array is _not_ standard c++ and not supported by all compilers.
On top of that it is less resource-friendly.
Stick to dynamically allocated arrays.
Notes:
Line 6: Initialize your variables
Line 9: Uniform initialization is preferred
@main: Missing return statement
"Although it looks like we’re deleting a variable, this is not the case! The pointer variable still has the same scope as before, and can be assigned a new value just like any other variable." So, after I dynamically allocate some memory, I delete it, then can I still use the pointers and use them to point to other addresses?
Hi Cosmin!
Yes
Output
Thank you for answering my question. Also, another one raised by answering this one, if you don't mind. You said "Be careful not to delete both @pAppleCound and @pBananaCount now, they point to the same memory.", can you give me more context, please?
@pAppleCount and @pBananaCount point to the same memory, let's say 0x1000. The int value at 0x1000 is 3.
When we run
the memory at 0x1000 will be marked as unused so it can be re-used by the operating system. The value at 0x1000 might still be 3, it might have been changed, anyway, we shouldn't access it anymore.
If we now run
you are trying to delete the memory at 0x1000 again. Oops, there is nothing, crash.
The same happens if we first delete @pAppleCount and then @pBananaCount, since they point to the same memory.
Oh, I understand! Thank you very much!
In this last case presented by @nascardriver, if some other program (or even worse, your OS) has scooped up the memory at 0x1000 for its own use and you delete pAppleCount and delete pBananaCount, will it throw an exception, crash your program, or could you potentially delete something your OS is using?? Seems like a great way to accidentally BSOD your PC if not careful!
Hopefully there are safeguards against this, lol.
> some other program
Every process has it's own address space which is not shared with other processes. If this was not the case you could perform meltdown/spectre like attacks by accessing dangling pointer and hoping to find sensitive data.
> throw an exception, crash your program, or could you potentially delete something your OS is using
No, the pointer is pointing to valid memory, just not the same memory as before
> accidentally BSOD your PC
There are few ways for user-mode programs to cause a BSOD. Every process runs in a VM-like environment to prevent your whole PC from crashing when a single process encounters a problem. BSOD are usually caused by drivers, as they run closer to the hardware.
Don't quote me on the things I said, I might be wrong.
Hi,
I tried the following simple code:
As I expected, dereferencing ptr will yield a garbage value and printing ptr gives an arbitrary address. I was surprised when i was rerunning the program several times. It turns out that ptr points to a new address each time (which i expected), but *ptr always gives the same value (22 in my case).
My imagination was that an uninitialized or unassigned variable or allocated piece of memory will show whatever value was at its address before declaring the variable or pointer. But obviously my program does assign a value upon memory allocation. Or is 22 stored everywhere by default? :-)
In a debug build target, some compilers will auto-initialize memory. I'm not sure whether you're seeing that, or whether you're just seeing undefined behavior that happens to appear consistent. :)
Hi Alex
What's the point of dynamically allocating a variable that isn't an array (e.g. new int {5}). I can see why it would be useful to have an array as you don't know the size at compile time but not for the single variables.
Thanks
Hi Ben!
There are more uses of pointers, you'll come across them when you start working on complex projects.
There's pretty much no reason I can think of to allocate fundamental types dynamically.
However, it is sometimes the case that we want to allocate a large struct dynamically (because it might be too large to want to keep on the stack) -- and the struct is treated as a scalar (singular) value, not an array. We cover the stack and heap next chapter, which might help shed some light on this answer.
Later on, you'll also learn about classes, which are similar to structs. These are also sometimes allocated dynamically. We'll see examples of this when we cover classes.
Hello, can you clear up my confusion of your usage of "if (!value) // handle case where new returned null". I am just confused what exactly "!" is supposed to represent. So far we've used it to represent if(!boolVariable) to test whether a variable is true or false, but I'm confused on how it being used in if(!boolVariable) relates to if (!value).
Thanks -Jeffery
Hi again Jeffery!
You're right in saying "!" negates boolean values (true becomes false, false becomes true).
Let's first look at what happens when we use "if" on an int pointer without "!":
This snippet will print "Hello", but why? We put in an int pointer where we're supposed to write a boolean.
What happens is, the compiler or cpu will find some way of converting the pointer to a boolean. It will look at the pointer, which is 0x897234AB for example, and see, that it's not 0x00000000. This means, that the boolean value of the pointer is true. This works the same way for numeric values. 0 means false, everything else is true.
When adding the "!" before the pointer, the pointer will first be converted to a boolean, then it will be negated. By writing
you are actually checking if pValue is 0, because
Case 1 (pValue is not 0): Converting pValue to a boolean is true and !true is false.
Case 2 (pValue is 0): Converting pValue to a boolean is false and !false is true.
To avoid confusion I suggest you to use boolean operations to create the boolean value required for the if statement. For pointers you should check against nullptr, which is available since c++11, otherwise check for 0.
Thank you so much!
! is a logical negation, flipping a true boolean to false, or vice-versa. If value is null, then that is boolean false. So if (!variable) is a shorthand way of writing "if (variable == false)", which will be the case if variable is boolean false, integer 0, or nullptr.
Hi Alex,
I have got confused after going this section on dynamic memory allocation.
My understanding was that every process has got it's own heap segment. So when a process asks for a dynamic memory OS will allocate memory from heap segment assigned for that process.
but when I went to section "How does dynamic memory allocation work?" you have mentioned - <it can return the memory back to the operating system to be given to another program>. How come it can happen if we have different heap segment for different processes. FYR - https://stackoverflow.com/questions/1952019/heap-stack-and-multiple-processes
So here's my current understanding (which may be inaccurate, as modern OS and hardware function isn't my core area of knowledge -- if anybody is aware of any inaccuracies here, please point them out).
Each executable in a modern OS has:
* A heap segment, which is where heap memory is kept track of
* A virtual address space (see https://en.wikipedia.org/wiki/Virtual_address_space).
When your program allocates dynamic memory, the heap memory expands to "reserve" that memory for your program. But those memory address are virtual.
What actually happens is that your OS has a virtual memory subsystem that maps virtual addresses that your program uses to physical memory addresses (or swap space on your storage devices). So although your heap space has expanded, the OS has actually reserved some memory out of the global pool for your use. When you access the heap memory, you're really being transparently redirected to the actual storage location (in physical memory, or on a disk).
So when you deallocate memory, the heap inside your process shrinks, as those virtual addresses are no longer needed. Those virtual addresses aren't reassigned to another process -- they're owned by your process. However, the actual physical memory that was mapped to those virtual addresses can be reallocated to another process that is requesting memory.
The good news is that understanding how this works isn't required to use C++. So long as you understand that the stack is fixed in size and the heap is extensible, and when each is used, you don't have to know how the OS handles the underlying management (even though it's interesting).
Thanks a lot Alex for the response. Nice explanation, It really cleared my doubt.
Cud u plz make a tutorial on linked list through pointers and implementation in stacks,I hv some doubts in that part
I do not understand this expression.
First, it declares a variable called `value`, as a pointer to an int.
Then it uses move constructor to initialize `value` with the rvalue.
But what does expression of this rvalue mean?
std::nothrow is a constant of type std::nothrow_t - it's not a keyword, nor a type for this to be some sort of a casting. All I can understand is that std::nothrow_t overrides operator new. But what does remaining `(std::nothrow) int` mean?
> But what does expression of this rvalue mean?
I don't understand this question.
> But what does remaining `(std::nothrow) int` mean?
std::nothrow is a constant of type std::nothrow_t used to disambiguate the overloads of throwing and non-throwing allocation functions. The new operator has throwing and non-throwing allocation functions -- this allows us to pick the non-throwing one.
Oh, so it's actually a part of the `new` keyword syntax.
I thought it was some trick of wrapping int type with something else, and then calling a new on it. I've checked syntax here: http://en.cppreference.com/w/cpp/language/new
so std::nothrow is the placement_params part?
It would appear so. :)
Under Operator new can fail, we have:
int *value = new (std::nothrow) int; // value will be set to a null pointer if the integer allocation fails
But isn't null pointer in dynamic memory means that no memory has been allocated to this pointer. Setting value to null pointer implies the wrong thing in above statement, right?
If the allocation fails, then no memory has been allocated to the pointer, so it seems fitting that the pointer be set to null. It also gives us a way to test whether the allocation succeeded: null means failed, non-null means success.
Thanks Alex. Awesome tutorials.
What will dereferencing a null pointer cause?
It causes undefined behavior, but most often manifests as a crash.
Thanks,Alex
Which OS can automatically delete the dynamically allocated space in heap if in case it is not deleted explicitly
I would expect all modern, consumer operating systems to do this. I can't speak to specialized operating systems, like those that go into embedded devices.
Then what's the use of delete operator if OS is there to deleted it for you
The OS only deletes the memory once your program has ended. Memory that is no longer used by your program but is not deleted while your program is running is lost (called a memory leak) until the program ends. If your program runs for a long time, these leaks can add up and eat up all your free system memory, leading to slow performance of not just the program running, but your entire system.
Thanks for the answer.Btw are u a teacher?
As a profession, no. Informally, very much so.
Cud u plz make a tutorial on linked list through pointers and implementation in stacks,I hv some doubts in that part
Hi Alex,
I have a doubt.
when you allocate a memory requested from the operating system it holds the address of that memory, right?
but when you try to get the address of that memory(as output) it constantly changes (different output each time).
why do this happen?
Because every time you run your program, the OS is giving you a different address. The address is constant over the life of your program, but different across each execution.
Nice article. 1 doubt, "Second, how do we tell which bits of memory are actually used?" Can you please elaborate this problem with example. Thanks.
Consider a list of names of students in a class of max size 30. We can reasonably allocate 30 strings. But what if there are only 25 students in the class? That's okay, because we can leave the last 5 names as empty strings, and it's easy to tell which ones are allocated but not used. But what about our Monster array? It can hold up to 40 monsters max. But what if our dungeon only had 30 monsters in it? How do we tell that the last 10 entries were allocated (to ensure we could hold 40 if we needed to) but were not used? That's a solvable problem, but one that adds complexity, as it may be different for each array.
Does that make sense?
Thanks Alex. Got your point - additional complexity gets added.
Alex, can you explain how would you solve the problem?
I'd first type to avoid the problem by using dynamic allocation to only allocate exactly as many objects as I needed. If that wasn't possible, then the best thing to do would probably use a separate "length" variable to keep track of which entries in the array were valid (e.g. if the array could hold 40 Monsters, a length of 30 would imply the first 30 were valid). This does require that all of the Monsters in the left-most part of the array are valid, but in most cases that will be doable.
Hi, Alex.
You said: "Second, when you delete a pointer, if that pointer is not going out of scope immediately afterward, set the pointer to 0 (or nullptr in C++11)." What you mean under "going out of scope immediately afterward". If I have deleted pointer and no using it in my program lately - then it means that pointer went out of scope immediately?
By "going out of scope immediately" I mean the variable will be destroyed immediately thereafter (e.g. because the variable has block scope and the block has ended). Basically, if the pointer is going to get destroyed, there's no point in setting it to 0 just before it gets destroyed. If your pointer is not going to get destroyed immediately though, you should set it to 0 whether you use it again or not, just to be safe (maybe you'll change your mind later).
I didn't understand just one thing, if i'm using dynamic memory allocation for an int for example (int *ptr = new int), am I cappable of using more than 4 bytes, so using the number 32768 wouldn't overflow the variable?
Just one more thing (i remembered after posting it), some games are really bad optimized, could that be the case of memory leak ?
Could be. If you notice the memory that a game consumes tends to grow over time, there's probably a memory leak. That will impact performance when enough memory has leaked that the system starts running low on free memory.
No, dynamically allocated variable have the same range as non-dynamically allocated variables.
Hi, Dear Alex when you said
When you dynamically allocate memory, you’re asking the operating system to reserve some of that memory for your program’s use. If it can fulfill this request, it will return the address of that memory to your application. From that point forward, your application can use this memory as it wishes. When your application is done with the memory, it can return the memory back to the operating system to be given to another program.
Does the operating system allocate a bunch of address to the program or just one address?
Either, depending on what you ask for. However, it only returns one address (the lowest address -- if you asked for more than one address, you can assume it will be sequential).
Thanks for the answer. :)
Hi Alex.
You said that pointer don't get deleted when go out of scope.
Pointer follow normal variable scoping rules.
And when automatic variable go out of scope, they are destroyed.
So can I conclude that when a pointer go out of scope(not a global pointer,which is destroyed at the end of the program), it is destroyed?
Yes, when a local pointer goes out of scope, it is destroyed. The memory being pointed to by the pointer is _not_ deleted. That has to be done manually via the delete keyword before the pointer is destroyed.
Hi Alex,
Lets say i use automatic allocation for a string and just like in your example i initialize it to be an array of 25 chars. Does the extra memory that i could save by using dynamic allocation - lets say 10 bytes - actually matter?
Not really, since we just have one array. It starts to matter more than you have lots of objects. Or when you want to explicitly control when the object gets destroyed.
Hello! Alex,I didn't understand why dereferencing null pointers leads to undefined behaviour.
Also,please explain memory leaks once more,please!!!
The C++ standard specifies that dereferencing a null pointer leads to undefined behavior. Most typically, this will cause your program to terminate.
Conceptually, this makes sense. Dereferencing a pointer means "go to the address the pointer is pointing at and access the value there". A null pointer doesn't have an address. So when you try to access the value at that address, what should it return?
Memory leaks happen when your program asks the operating system for memory but then loses the address of that memory before giving it back to the operating system. This memory then can't be returned back to the operating system (until the program terminates), and it also can't be reused for anything else (because the operating system thinks the program is still using it).
This is essentially an artifact of the fact that C++ doesn't have any kind of garbage collection system.
What's the meaning of termination of program?
Termination = the end, so when your program terminates, it stops running, and the operating system removes it from memory.
Alex,
Does it make a "practical" sense to write a loop for memory allocation? In other words, if at first attempt OS says:"No memory for you", then it does not matter how many times you ask for memory, you are not going to have any :). Let's say I don't want to terminate the program but willing to wait until OS gives the memory. Thanks.
int *value = nullptr;
int numberOfAttempts = 0 ;
int maxNumberOfAttempts = 10 ;
while (!value) // handle case where new returned null
{
value = new (std::nothrow) int; // ask for an integer's worth of memory
++numberOfAttempts;
if (numberOfAttempts > maxNumberOfAttempts)
{
// Do error handling here
std::cout << "Could not allocate memory";
break ;
}
}
If you want to keep trying, you're welcome to. Maybe memory will free up if the user terminates some other applications, or frees up some hard drive space (since the OS can page stuff out to disk). But I definitely wouldn't do it in a loop that will iterate so quickly. I'd sleep the program so the loop iterates only once every few seconds. That way you're not slamming the OS with requests it can't fulfill.
Hello Alex!
(Reference to our first program ever)
I copy-pasted the following code from the tutorial to Code::Blocks -
I was expecting unxepected results. Well, the resuls were unexpected indeed.
IT PRINTS 7!!!!!!
Could you please throw some light on why that happened?
Not really. The nature of "undefined behavior" is that it may actually work sometimes, or even all of the time. See http://www.learncpp.com/cpp-tutorial/13-a-first-look-at-variables-initialization-and-assignment/ for more information on undefined behavior.
Alright. Thanks!
Idk why it printed 7 on yours, but in Visual Studio 2017 community Edition + other online compilers, it either crashed or printer 0. (successfully compiled tho)
Everytime i compile this program, it prints diff. memory address?
it is due to overwriting of the prev. memory allocation everytime i compile/run the prog...??
The operating system is giving your program different pieces of memory when it's run at different times.
Exactly.Ok.Thanks.