Why doesn't new in C++ return NULL on failure

后端 未结 8 775
别那么骄傲
别那么骄傲 2020-12-29 19:17

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

8条回答
  •  [愿得一人]
    2020-12-29 19:22

    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).

    Aside

    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?

提交回复
热议问题