Why does not std::nothrow work as expected in gcc(

2019-02-26 20:10发布

I've seen lots of people in my team checking null pointers like this:

    SomeClass *pSc = new SomeClass;
    if ( NULL == pSc )
    {
        // cope with error
    }

I known this will not work, because new operator in c++ throws a std::bad_alloc exception instead of returning NULL. I also know that std::nothrow can make what they expected really happen. So I wrote an example like this:

    #include <iostream>
    #include <limits>
    #include <new>
    using namespace std;

    void myNewHandler()
    {
        std::cerr << "Failed to allocate memory!" << std::endl;
    }

    int main(int argc, char* argv[])
    {
        //std::new_handler oldHandler = std::set_new_handler(myNewHandler);

        int *pLotsMem = new(std::nothrow) int[std::numeric_limits<long long>::max()];
        if ( nullptr == pLotsMem )
        {
            std::cerr << "Allocation failed" << std::endl;
            return -1;
        }
        else
        {
            delete[] pLotsMem;
            pLotsMem = nullptr;
        }

        //std::set_new_handler(oldHandler);

        return 0;
    } 

Yes, I wanted to demonstrate usage of std::set_new_handler as well. To my surprise, even this did not work. new operator still threw an exception(std::bad_array_new_length, a derived class of std::bad_alloc) and then terminated the program.

Any idea why this failed to work? How should one check pointers returned by new operator in gcc?

标签: c++ g++
1条回答
混吃等死
2楼-- · 2019-02-26 20:28

Believe or not, this is standard compliant behavior:

5.3.4/7

The expression in a noptr-new-declarator is erroneous if:
[...] — its value is such that the size of the allocated object would exceed the implementation-defined limit (annex B); or
[...]

If the expression, after converting to std::size_t, is a core constant expression and the expression is erroneous, the program is ill-formed. Otherwise, a new-expression with an erroneous expression does not call an allocation function and terminates by throwing an exception of a type that would match a handler (15.3) of type std::bad_array_new_length (18.6.2.2). When the value of the expression is zero, the allocation function is called to allocate an array with no elements.

In short, non-throwing allocator function is not even called, exception is thrown by new-expression itself.

I assume that you are not using modern C++ version, because in those std::numeric_limits<long long>::max() marked as constexpr and is a core constant expression, which yields compile-time error.

Clang, probably has implementation-defined limit set higher than max value of long lond, bypassing this quirk of C++.

查看更多
登录 后发表回答