Я думаю, что это очень просто, и вы перепутали две принципиально разные вещи:
malloc () может вернуть все, в частности ноль.
глобальная функция распределения C ++ void * operator new(size_t) throw(std::bad_alloc)
требуется стандартом либо для возврата указателя на требуемый объем памяти (+ соответствующим образом выровненный), либо для выхода через исключение.
Если вы хотите заменить функцию глобального распределения, вы несете ответственность за предоставление замены, которая соответствует правилам стандарта. Простейшая версия выглядит так:
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;
}
Любая серьезная реализация на самом деле должна содержать цикл для вызова зарегистрированного нового обработчика до тех пор, пока распределение не будет выполнено успешно, и выдается только при отсутствии новых обработчиков.
Программа, которую вы написали, просто плохо сформирована.
Отступление: Почему это new
определено таким образом? Рассмотрим стандартную последовательность распределения, когда вы говорите T * p = ::new T();
. Это эквивалентно этому:
void * addr = ::operator new(sizeof(T)); // allocation
T * p = ::new (addr) T(); // construction
Если вторая строка выбрасывает (т.е. конструирование завершается неудачно), память освобождается с помощью соответствующей функции освобождения. Однако, если первый вызов заканчивается неудачей, выполнение никогда не должно доходить до второй строки! Единственный способ добиться этого - выйти через исключение. (Версии без выделения функций распределения предназначены только для ручного использования, когда пользовательский код может проверить результат работы распределителя, прежде чем приступить к построению.)