I think this is very simple, and you have two fundamentally different things, confused:
malloc () can return anything, in particular zero.
C ++ standard distribution function void * operator new(size_t) throw(std::bad_alloc) is required by the standard in order to either return a pointer to the required amount of memory (+ appropriately aligned) or otherwise exit the exception.
If you want to replace the global distribution function, it is your responsibility to provide a replacement that complies with the rules of the standard. The simplest version looks like this:
void * operator new(size_t n) throw(std::bad_alloc) { void * const p = std::malloc(n); if (p == NULL) throw std::bad_alloc(); return p; }
Any serious implementation should actually contain a loop to call the registered new handler until the distribution is successful, and just throw it away when there are no more new handlers.
The program you wrote is simply poorly formed.
Digression: why is this new defined this way? Consider the standard distribution sequence when you say T * p = ::new T(); . This is equivalent to this:
void * addr = ::operator new(sizeof(T));
If the second line throws away (i.e. the design does not work), the memory is freed using the corresponding deallocation function. However, if the first call failed, the execution should not reach the second line! The only way to achieve this is to get out of the exception. (Distribution options without throwing are intended only for manual use, when the user code can check the result of the dispenser before proceeding with construction.)
source share