What are all the other things a new operator does other than allocating memory and calling a constructor?
Depends on if it's overloaded or not, if you built the app for debugging, if you're using a memory leak detector, if you have some kind of memory pooling scheme, if you have something like the Boehm garbage collector that's marking/unmarking bits, etc., etc. It could be doing a lot of custom stuff inside, or nothing special at all.
The C++ standard has this to say about the single object form (the form usually used) of the new operator from the <new>
header:
Required behavior:
Return a nonnull pointer to suitably aligned storage (3.7.3), or else throw a bad_alloc exception. This requirement is binding on a replacement version of this function.
Default behavior:
— Executes a loop: Within the loop, the function first attempts to allocate the requested storage. Whether the attempt involves a call to the Standard C library function malloc is unspecified.
— Returns a pointer to the allocated storage if the attempt is successful. Otherwise, if the last argument to set_new_handler() was a null pointer, throw bad_alloc.
— Otherwise, the function calls the current new_handler (18.4.2.2). If the called function returns, the loop repeats.
— The loop terminates when an attempt to allocate the requested storage is successful or when a called new_handler function does not return.
The standard has a lot of other stuff to say about the new operator and dynamic memory allocation (an awful lot to say), but I think the "Default behavior" list sums up the basics of the new operator pretty well.
I've written a explanation of what it does in this answer. It explains how
new
gets the memorynew
handles memory failurenew
handles constructor exceptionsnew
handles special placement and nothrow versions
Michael explained how the default allocator function (::operator new) gets memory nicely and how it handles failure. I've seen your question on where the size of an object is stored in his comments. The answer is, there isn't size stored if not necassary. Remember that C doesn't need the size for free
(and ::operator new can just use malloc
):
void * memory = malloc(x);
free (memory); // no need to tell it the size
Here is an example where you see how storing the size has an impact on the size of allocation for the array form of a new expression (not covered by my other answer):
#include <cstddef>
#include <iostream>
struct f {
// requests allocation of t bytes
void * operator new[](std::size_t t) throw() {
void *p = ::operator new[](t);
std::cout << "new p: " << p << std::endl;
std::cout << "new size: " << t << std::endl;
return p;
}
// requests deleting of t bytes starting at p
void operator delete[](void *p, std::size_t t) throw() {
std::cout << "delete p: " << p << std::endl;
std::cout << "size : " << t << std::endl;
return ::operator delete[](p);
}
};
int main() {
std::cout << "sizeof f: " << sizeof (f) << std::endl;
f * f_ = new f[1];
std::cout << "&f_ : " << f_ << std::endl;
delete[] f_;
}
It will print out something like this:
sizeof f: 1
new p: 0x93fe008
new size: 5
&f_ : 0x93fe00c
delete p: 0x93fe008
size : 5
One byte for the object itself and 4 bytes for the count which is stored just before the allocated area of the object. Now if we use the deallocation function without a size parameter (just removing it from the operator delete), we get this output:
sizeof f: 1
new p: 0x9451008
new size: 1
&f_ : 0x9451008
delete p: 0x9451008
The C++ runtime here doesn't care about the size, so it doesn't store it anymore. Note that this is highly implementation specific, and that's what gcc does here to be able to tell you the size in the member operator delete. Other implementations may still store the size, and will most likely if there is a destructor to invoke for the class. For example just adding ~f() { }
above makes gcc to store the size, regardless on what deallocation function we write.