C ++ New crash principle and Solution

Source: Internet
Author: User

C ++ New crash principle and Solution

Most C ++ developers use STL extensively in their code. If you use STL and Visusal Studio 6.0 directly, your program will be very likely to crash when the memory is low. The reason is that the results of the new operation are not verified. Worse, if the new operation does fail, there is no standard for the feedback-Some compilers will return NULL pointers, and some will throw an exception. In short, if you use STL in an MFC project, note that MFC has its own rules. This article mainly discusses these issues and explains how the default behavior of the latest Visual C ++ compiler has changed, it also provides an overview of some modifications you must make when using Visual C ++ 6.0, so that you can safely use STL even if the new operation fails.

 

 

Background

How many programmers will check whether the new operation fails? Is this check frequently required? I have seen some large and complex C ++ projects written in Visual C ++ 6.0, but I have not seen a check on whether the returned result of new is NULL. Please note that the new return NULL check. In Visual C ++ 6.0, the default action when the new operation fails is to return a NULL pointer instead of throwing an exception. In Visual C ++ 2003, NULL is returned when the new of the c Runtime Library fails, but the Standard C ++ Library) when the new in fails, an exception is thrown. What kind of behavior is when New fails depends on whether the linker is in front of the Standard C ++ library or the C Runtime Library. If the standard C ++ library is in front, an exception is thrown. If the C Runtime Library is in front, only NULL is returned. To rewrite this behavior and force the new that will throw an exception, we need to display the link thrownew. obj. In Visual C ++ 2005, 2008, and 2010, unless the link nothrownew. obj is displayed, an exception is thrown in both the C Runtime Library and the Standard C ++ library. In addition, the behavior described here does not involve hosting code or. NET Framework. If the original Visual C ++ 6.0 code is not expected to throw an exception in the new operation, after porting all the code to the high-version compiler, an exception will be thrown in the new one, the program may be terminated unexpectedly during running. Pay attention to this point.

The C ++ Standard specifies that the new operator must throw an exception upon failure. Specifically, this exception must be std: bad_alloc. This is only a standard. For more information about Visual C ++, see the following table:

Pure C ++ MFC

Visual C ++ 6.0 Returns NULL. CMemoryException
> 6.0 Std: bad_alloc CMemoryException

It can be seen that the exception thrown in the MFC environment is not required by the C ++ standard. If you use catch (std: bad_alloc) in STL to handle memory allocation failures, this can only be done in environments without MFC. STL in Visual C ++ 6.0 uses catch (...) To handle new failures. This method can work normally in MFC.

Returns the NULL new operator.

In two cases, you do not need to check whether the pointer returned by new is NULL: new will never fail or new will throw an exception.

Even if you think that new will never fail, it is a bad programming habit to not check the return value. Desktop applications are unlikely to suffer from memory depletion. However, applications that require 24 hours of operation on some servers may run out of memory, especially on a shared application server. If you cannot guarantee that your application will never leak a byte, the chance of memory errors will increase.

If you do not check whether the returned pointer is NULL because new throws an exception, this is also excitable. After all, the C ++ standard requires that new should throw an exception upon failure, but this is not the default method of Visual C ++ 6.0, it will only return a NULL pointer. Although later versions support the C ++ standard, the practices in section 6.0 (especially when used with STL) may cause problems. In STL, it is assumed that an exception will be thrown when new fails, regardless of the compiler used. In fact, if new does not show this behavior and gets a NULL pointer due to memory allocation failure, the next behavior of STL will be unpredictable, and the program may crash.

Standard Template Library

Developers are increasingly dependent on STL in the C ++ development process. STL provides many classes and functions based on the C ++ template. STL has several advantages: first, this library provides a consistent interface for a variety of common tasks; second, this part of code has been widely tested, therefore, we can think that it has no bugs. Finally, the algorithms in it are also the best.

To enable STL, the compiler must support the C ++ standard. The Visual C ++ compiler is pre-installed with an STL, which can be used by other manufacturers.

Visual C ++ 6.0 and new operators

If new fails, NULL is returned. This behavior is considered a Bug because it is inconsistent with the standard. All STL implementations, including those included in Visual C ++, are expected to throw an exception when the new operator fails. Although it can change the behavior of new so that it throws an exception when encountering an error, this will bring more irregularities. The following code describes the problem:

1. #include < string > 2. void Foo() 3. { 4. std::string str( A very big string ); 5. } 6.

In Visual C ++ 6.0, the above Code will eventually call the following function in STL (excerpt, for the convenience of illustration, the redundant code has been removed ):

01. void _Copy(size_type _N) 02. { 03. ... 04. _E *_S; 05. _TRY_BEGIN 06. _S = allocator.allocate(_Ns + 2, ( void *)0); 07. _CATCH_ALL 08. _Ns = _N; 09. _S = allocator.allocate(_Ns + 2, ( void *)0); 10. _CATCH_END 11. ... 12. _Ptr = _S + 1; 13. // ACCESS VIOLATION 14. _Refcnt(_Ptr) = 0; 15. ... 16. } 17.

In the try statement block, the return value of allocator. allocate is assigned to the local Variable _ S, while allocator. allocate uses new. The default behavior of Visual C ++ 6.0 is: NULL is returned when the new operator fails, which makes the value of _ s null. The next line will assign the value of _ S + 1 to _ Ptr. If _ S is NULL, _ Ptr is 0x00000001. The next sentence _ Refcnt (_ Ptr) = 0 actually Returns _ Ptr-1 (I .e. _ Ptr [-1]), that is, it is actually in the calculation of the NULL originally returned. _ Refcnt returns a NULL pointer, and then assigns 0 to it (* NULL = 0), which immediately generates an access conflict error. Although this seems to be a Bug, the STL code is actually no problem, just to get a correct behavior, it needs new to throw an exception.

Let's look at the execution process that throws an exception when new fails. Execute allocator. allocate first. If new fails, the std: bad_alloc exception will be thrown, and then _ CATCH_ALL will be executed and try again. If the second allocation fails, another std: bad_alloc exception will be thrown, which will be propagated all the way to our code, leading to std :: although the stting object is defined, it is still null.

Modify the new operator

01. #include < new > 02. #include < new.h > 03. #pragma init_seg(lib) 04. namespace 05. { 06. int new_handler( size_t ) 07. { 08. throw std::bad_alloc(); 09. return 0; 10. } 11. 12. class NewHandler 13. { 14. public : 15. NewHandler() 16. { 17. m_old_new_handler = _set_new_handler(new_handler); 18. } 19. ~NewHandler() 20. { 21. _set_new_handler(m_old_new_handler); 22. } 23. private : 24. _PNH m_old_new_handler; 25. } g_NewHandler; 26. } // namespace 27.

If the above Code is included in our project, the error handling will be automatically modified when new fails, and std: bad_alloc will be thrown in this example.

New (std: nothrow) throws an error

In Visual Studio 6.0, if the above Code is included and the new (std: nothrow) is used for memory allocation, an error is reported when release is run, and the Abnormal program termination is displayed. This is a matter of detail, due to compiler optimization. You can go to Project Settings | C/C ++ | General | Optimizations to disable optimization to avoid this problem, or you can write a new (std: nothrow) by yourself) (See the source code NewNoThrow. cpp ).

Summary

The new operations provided by Visual C ++ 6.0 by default are not compatible with STL. Even if some solutions are mentioned above, it may be difficult to use a third-party library or some other functions in STL. In VC 6.0, the imbalance between new, new (std: nothrow) and STL cannot be completely solved. However, if the above method is not used, it will certainly be very troublesome.

In the MFC project, whether the new field in STL can withstand the exception test depends entirely on how the error is written during error handling in STL. Most will use catch (...) Instead of catch (std: bad_alloc), but this is not necessary.

Finally, as mentioned at the beginning, Visual C ++ 2005 to 2010 have fixed these problems.


Instance:

 


 

Related Article

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.