Handling of C + + new failure

Source: Internet
Author: User

As we all know, it is good programming practice and necessary to write a reliable program to check whether its return value is a "null pointer" (that is, to check the success of the operation of allocating memory) when using a function that allocates memory, such as Malloc/calloc. However, if you simply apply this trick to new, that is not necessarily true. I often see code like this:

int* p = new Int[size];
if (p = = 0)//check if p is null pointer
return-1;
Other code

In fact, the IF (p = = 0) Here is completely meaningless. In C + +, if new allocates memory fails, the default is to throw an exception . Therefore, if the allocation is successful, p = = 0 will not be established, and if the allocation fails, will not execute if (p = = 0), because the allocation fails, new will throw an exception to skip the following code . If you want to check if new is successful, you should catch the exception :

try {
int* p = new Int[size];
Other code
} catch (const bad_alloc& e) {
return-1;
}

It is said that some old compilers, new if allocating memory failed, is not thrown exception (presumably because C + + has not yet joined the exception mechanism), but like malloc, return null pointer. But I've never met a situation where new returns a null pointer.

Of course, standard C + + also provides a way to suppress the new throw exception and return a null pointer:

int* p = new (std::nothrow) int; This will not throw an exception if new fails, but instead returns a null pointer
if (p = = 0)//And so on, this judgment is meaningful.
return-1;
Other code

=============================== detailed ===================================

First, by the C + + standard, new failure throws a Bad_alloc exception, but some compilers do not support the C + + standard very well, such as new failure in vc++6.0 does not throw an exception, and returns 0.

The practice of not supporting C + + standards is as follows

Double *ptr=new double[1000000];

if (0 = = ptr)

...... Processing failed ...

Standard recommended procedure one.

Try

{

Double *ptr=new double[1000000];

}

catch (Bad_alloc &memexp)

{

After failure, either abort or redistribute

Cerr<<memexp.what () <<endl;

}

Standard Recommended Procedure II

is to use the Set_new_handler function to handle new failures. It is roughly defined in the header file <new> as follows:

typedef void (*new_handler) ();

New_handler Set_new_handler (New_handler p) throw ();

As you can see, New_handler is a custom function pointer type that points to a function that has no input parameters and no return value. Set_new_handler is a function that inputs and returns the New_handler type.

The input parameter of the Set_new_handler is a pointer to the error handler to invoke when operator new allocates memory fails, and the return value is a pointer to the old error handler that was already in effect before the Set_new_handler was called.

You can use Set_new_handler as follows:

function to call if operator new can ' t allocate enough memory

void Nomorememory ()

{

Cerr << "Unable to satisfy request for memory\n";

Abort ();

}

int main ()

{

Set_new_handler (nomorememory);

int *pbigdataarray = new int[100000000];

...

}

operator new cannot satisfy a memory allocation request, the New-handler function is not just called once, but is repeated until enough memory is found. Code that implements a repeating call can be seen in clause 8, where I use descriptive language to illustrate that a well-designed New-handler function must implement one of the following functions.

• Generate more usable memory. This will make it possible for the next attempt to allocate memory for operator new to succeed. One way to implement this strategy is to allocate a large block of memory at program startup and then release it the first time you call New-handler. When released with some warning messages to the user, such as too little memory, the next request may fail unless there is more free space.

• Install another different New-handler function. If the current New-handler function does not produce more available memory, it may know that another New-handler function can provide more resources. In this case, the current New-handler can install another new-handler to replace it (by calling Set_new_handler). The next time operator new calls New-handler, it will use the one that was recently installed. (Another workaround for this strategy is for New-handler to change its own run behavior, and it will do something different the next time it is called.) The method is to enable New-handler to modify static or global data that affects its behavior. )

• Remove New-handler. This means passing a null pointer to Set_new_handler. A standard Std::bad_alloc-type exception is thrown when New-handler,operator new is not installed to allocate memory unsuccessfully.

• Throws Std::bad_alloc or other types of exceptions inherited from Std::bad_alloc. Such exceptions are not captured by operator new, so they are sent to the place where the memory request was originally made. (Throwing other different types of exceptions would violate the operator new Exception specification.) The default behavior in the specification is to call abort, so when New-handler throws an exception, make sure it is inherited from Std::bad_alloc. Want to know more about exception specification)

• no return. A typical practice is to call abort or exit. Abort/exit can be found in the standard C library (as well as the standard C + + library).

The choice above gives you a great deal of flexibility in implementing the New-handler function.

For more information, please refer to "Effective C + +"

————————————————————————————————————————————————————————————

Recommended 30:new for proper handling after memory failure

There should be a lot of programmers who have heard this quote from Bill Gates:

For any one person, 640KB should be enough. (640K ought to is enough for everybody.)

Unfortunately, the great Bill Gates also made a slip of the tongue. With the development of hardware, memory becomes larger, but it still seems unable to meet the growing demand for memory. So, when writing a program, our C + + programmers must also consider how memory requests will be handled when they fail.

In general, when we use new for memory allocation, we take the following approach:

    1. char *pStr = new String[size];
    2. if (pStr = = NULL)
    3. {
    4. ...//Error processing
    5. return false;
    6. }

Can you find the problem in the above code? This is a very hidden bug (bug).

We have followed a good tradition of the C era: when using a function that allocates memory such as malloc, be sure to check whether its return value is a "null pointer" and use this as a basis for checking the success of the allocated memory operation, which is a good programming habit, Test-for-null code. is also required to write reliable programs. However, this perfect form of processing must have a precondition: if new fails, its return value must be null. Only in this way can we ensure that the code that appears to be "logically correct and well-styled" works correctly.

So what exactly does the compiler do with new failure? Long ago, in the savage era of the C + + compiler, the C + + compiler preserved the handling of the compiler: when operator new failed to satisfy a memory allocation request, it returned a null pointer. This was once a reasonable extension of the malloc function of C. However, with the development of the technology, standard update, compiler has more powerful function, the class is also designed to be more beautiful, new era of the application of memory failed to have a fresh processing mode: Throw a Bad_alloc exception (exception). Therefore, in the new standard, the above Test-for-null processing method is no longer recommended and supported.

If you look back at the code snippet at the beginning of this recommendation, the IF (pStr = = 0) Suddenly becomes meaningless from a good code style. In C + +, if new allocates memory fails, the default is to throw an exception. Therefore, if the allocation is successful, PSTR = = 0 will definitely not be established, and if the allocation fails, will not execute if (pStr = = 0), because when the allocation fails, new throws an exception and skips the subsequent code.

To understand the mystery more clearly, first look at the relevant statement:

  1. Namespace Std
  2. {
  3. Class Bad_alloc
  4. {
  5. //   ...
  6. };
  7. }
  8. New and delete
  9. void *operator New (std::size_t) throw (Std::bad_alloc);
  10. void operator delete (void *) throw ();
  11. Array New and delete
  12. void *operator new[] (std::size_t) throw (Std::bad_alloc);
  13. void operator delete[] (void *) throw ();
  14. Placement New and delete
  15. void *operator new (std::size_t, void *) throw ();
  16. void operator delete (void *, void *) throw ();
  17. Placement array New and delete
  18. void *operator new[] (std::size_t, void *) throw ();
  19. void operator delete[] (void *, void *) throw ();

In the new operations family above, only operator new that is responsible for the memory request throws an exception Std::bad_alloc. If this exception occurs, it means that the memory is exhausted, or there are other reasons for the memory allocation failure. So, in accordance with the C + + standard, if you want to check if new is successful, you should catch the exception:

    1. Try
    2. {
    3. int* pStr = new String[size];
    4. ...//Processing codes
    5. }
    6. catch (const bad_alloc& e)
    7. {
    8. return-1;
    9. }

But there are some traces of old compilers that do not support this standard. At the same time, many of the code that existed before the standard was enacted would surely cause a lot of protests if it became porous because of standard changes. The C + + Standardization committee does not want to abandon these test-for-null code, so they provide another alternative form of operator new-nothrow to provide traditional failure-yields-null behavior.

The implementation principle is as follows:

    1. void * operator new (size_t CB, const std::nothrow_t&) throw ()
    2. {
    3. Char *p;
    4. Try
    5. {
    6. p = new CHAR[CB];
    7. }
    8. catch (std::bad_alloc& e)
    9. {
    10. p = 0;
    11. }
    12. return p;
    13. }

The overloaded version of Nothrow New is also declared in the file, which is declared in the following way:

  1. Namespace Std
  2. {
  3. struct nothrow_t
  4. {
  5. //   ...
  6. };
  7. extern const nothrow_t Nothrow;
  8. }
  9. New and delete
  10. void *operator New (std::size_t, std::nothrow_t const &) throw ();
  11. void operator delete (void *, std::nothrow_t const &) throw ();
  12. Array New and delete
  13. void *operator new[] (std::size_t, std::nothrow_t const &) throw ();
  14. void operator delete[] (void *, std::nothrow_t const &) throw ();

If you take the new form of a non-throwing exception, the code snippet at the beginning of this recommendation should be rewritten in the following form:

    1. int* pStr = new (std::nothrow) string[size];
    2. if (pstr==null)
    3. {
    4. ...//error-handling code
    5. }

According to recommendation 29, the compiler has completed two tasks in the expression new (Std::nothrow) classname. First, the nothrow version of operator New is called to allocate object memory for a classname. If this allocation fails, operator new returns a null pointer, and if the memory allocation succeeds, the ClassName constructor is called, and at this point the object's constructor can do whatever it wants to do. If it also needs new memory at this point, but does not use the Nothrow new form, then although the operator new called in "New (Std::nothrow) ClassName" does not throw an exception, its constructor inadvertently does something wrong. If it does, exception will propagate in the system like an exception thrown by the normal operator new. So using nothrow new only guarantees that operator new does not throw an exception, and that an expression such as "new (Std::nothrow) ClassName" does not throw exception. So, be cautious with nothrow new.

Finally, there is a special but real problem: in Visual C + + 6.0, operator new, operator new (Std::nothrow) and STL are incompatible, mismatched, and cannot be completely repaired. If you use the STL in Visual c++6.0 in a non-MFC project, its ready-to-use behavior may cause the application to crash if the STL is not in sufficient condition. For MFC-based projects, whether or not STL is immune to the problem depends entirely on the STL's exception handling for operator new. This is explained in detail in James Hebben's article, "Do not let memory allocation fail cause your legacy STL application to crash", if you are using the old Visual C + + 6.0 compiler and are interested in this issue, please Google.

Please remember:

When using new to request a block of memory failure, throw exception Std::bad_alloc is the standard behavior specified in the C + + standard, so the recommended use try{P = new int[size];} catch (Std::bad_alloc) {...} The processing method. However, in some old compilers, which do not support the standard, it will return null, at this time with C traditional Test_for_null code form will play a role. Therefore, we should adopt a reasonable disposition method for different situations.

Translated from: http://www.2cto.com/kf/201204/129171.html
Please respect the copyright of the original author

Handling of C + + new failure

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.