Discover more from Bitesized Engineering
What happens when you type the "new" keyword?
Chronicles of C++ Memory Management - Part 6
Hi there! 👋
It’s a new day and a new issue of Bitesized Engineering, fresh out of the oven. But this time I’m switching gears back to C++ & Memory Management (just like I promised!).
Last article of the Memory Management series discussed the Stack Attack, or - how attacks against Stack are usually done. And before that I spent quite some time discussing the Stacks (Stacks, heaps and other funny places, So, what is a Stack, really?, Why is Stack faster than Heap?, etc.). Now I’d like to shift focus to Heaps and Heap Allocations.
But before we do that, I feel there’s one important thing to answer - what happens when you type “new Bar();”? Yes, we all know that it constructs an object
on a heap, but how does that actually work? That’s what I’m deemed to answer this time :)
As usual, the infographic goes first and then the more detailed explanation.
As you can see, what really happens when you write “new” statement (in C++ at least) is:
Now I’d like you to stop and think for a second. You are a Computer. And somebody asks you to store some bits in your memory (remember the C++ and Data Types article? It’s all just bits!). What would you do to accomplish that? Give it couple of seconds, I’ll wait.
I’m guessing that one of the first things would be to ask - well, how MANY bits do you want to store? And then you’d proceed to find a place in memory that can house those bits. And once you do find that place - you’d probably PLACE the object there. And if you wanted to be OOP compliant, you’d also call a special method on the object, called “Constructor”.
Guess what - C++ is no different really! It’s exactly what it does as well. So if you say give me a
new CandyBar();, it will first go and figure the size of it (i.e.
sizeof(CandyBar)) and then it will go and ask OS where it can house those bits (in case of Windows, it would call HeapAlloc()). If OS says NO MEMORY FOR YOUR CANDY, MA’AM (e.g. your system is OUT OF MEMORY), then you’d probably want to throw an exception or something. But if there IS a memory, and OS gives you a memory location that can house your bits, then C++ proceeds and actually PLACES the object there (and calls a constructor).
void* operator new ( std::size_t count );
::(optional) new (placement-params) new-type initializer
The first one is, you guessed it,
operator new, and it’s job is to find a place to house your bits, and the second one is
placement new, which actually CONSTRUCTS the object in the memory space returned by
Putting it all together, it looks similar to this:
// Has to be included if you are using placement new #include <new> CandyBar* candy = new CandyBar("Snickers"); // could be re-written as: void* storage = ::operator new(size_t(candy)); // operator new CandyBar* candy = ::new(storage) CandyBar("Snickers"); // placement new
Couple of things to note here:
operator newreturns a
void*. If you’re wondering what the heck is a “void pointer” - it can literally be a pointer to ANYTHING. All you know is it’s a pointer to SOMETHING, but the rest you have no idea about.
::in front of
operator newis optional, but I added it for a reason, and the reason is that you might see it in a code and it could look scary. But it’s actually really simple - all it does is tell the compiler to use
operator newfrom GLOBAL namespace (i.e. use the DEFAULT
operator new). This is useful in cases where you suspect someone might have overloaded it.
new(storage) CandyBar(“Snickers”)is the
placement newsyntax. What it does is probably self-explanatory - it constructs the
CandyBarobject at the
Why is all of this relevant, one might ask. And to tell you the truth - it’s probably not. It seems to be highly unlikely that you will ever need to write your own allocator. But it’s useful to know that it’s a viable option.
Speaking of overloading
operator new -
operator new on your Class; or for the whole app! And reasons could be various, but some might be:
Pre-allocating a pool of memory when process starts and doing all allocations from THAT pool, or
Ensuring that objects are created on a Stack and not a heap (i.e. you could return a Stack address from
There’s probably lot more, but this is all from the top of my head.
Finally, one common misconception worth mentioning is that there is a belief that "new” creates objects on the Heap. That COULD be the case for other languages, but it’s certainly NOT the case for C++. Here’s what C++ reference says about it:
[new expression] creates and initializes objects with dynamic storage duration, that is, objects whose lifetime is not necessarily limited by the scope in which they were created.
As you can see, it says NOTHING about Stack or Heap or what have you. All it says is that if you want a long-lived object whose lifetime is NOT tied to current scope - you should use “new”.
What actually happens is that in most (or all of?) the default implementations, this memory actually does come from the Heap. But it doesn’t have to! From what I read (but never used) is that, technically speaking, you could return the memory address that is mapped to some I/O device (e.g. an SSD) and effectively construct your objects there.
Anyway, that would be about it for today :) If you enjoyed this article, do consider subscribing and sharing it with others.
In the meantime, here are the other articles from this series: