Why doesn\'t new
return NULL
on failure? Why does it throw an exception only on failure?
As it returns a pointer to the object on successes
In the comments, you emphasized that you wanted to know why new
is designed this way. In my mind, it's all about object composition.
Consider a class Foo which contains (among other things) a std::vector.
class Foo {
public:
explicit Foo(std::size_t n) : m_vec(n, 'A') {}
...
private:
std::vector m_vec;
...
};
When you construct a Foo in dynamic memory, there are two memory allocations: one of the Foo itself, and one for the contents of its vector. If either one fails, you need to be assured that there are no leaks and that the problem is reported to the caller.
Foo * pfoo = new Foo(desired_size);
Suppose new
did return a null pointer upon failure. If the allocation for the Foo fails, pfoo
will be set to a null pointer, and you could rely on that to do your error detection. Terrific. You then have some error handling code like:
if (pfoo == nullptr) { ... }
Now consider the nested object. If the allocation for the contents of m_vec
fails, you'd have to detect that and report it to the calling code, but there's no way for you to get a null pointer to propagate out to the assignment to pfoo
. The only way to do that is to have std::vector throw an exception (for any kind of construction problem), so the error handling code we just added would be useless because it's looking for null pointer instead of exceptions.
Having new
throw a std::bad_alloc
allows you to treat nested dynamic memory allocation failures the same way you treat outer ones. That's a powerful way to avoid code duplication and errors.
The C++ committee could have let new
return a null pointer on an allocation failure, but every constructor that used new
for internal memory would have to detect the failure and turn it into an exception anyway. So having new
throw by default simplifies everyone's code.
For those cases where your constructor can do something reasonable even in the face of an allocation failure, you can explicitly ask for the null pointer with std::nothrow
and then handle the error (or you can catch the std::bad_alloc
).
Also consider what happens if we stack allocate a Foo.
Foo foo(desired_size, 'B');
If we had somehow managed to make construction problems return a null pointer, how would the calling code detect it?