Freigeben über


Checking the result of new is a bug in C++

At least, it is a bug in VC8.  That check won't happen.  Reading Larry Osterman's recent posts "What's wrong with this code, part 15" and the answers, reminded me this behavior changed in VC8.  If you check the result of new in code compiled with VC8, your code is wrong.  The call to new will throw.  Yes, your code worked in 5.0, 6.0, (maybe) 7.0 and 7.1, but it doesn't now.

 

You can get the old behavior if you link with nothrownew.obj.  The linker will then make every call to new in your dll (or exe) non-throwing.   This is incompatible with STL, or any other code that relies on new throwing.

 

The only other option is to use std::nothrow placement new.  Don't do that. 

 

If you are writing code that uses no throw semantics, you probably need those same semantics from the libs you link as well.   If you are linking a lib that was coded expecting new to return NULL rather than throw, the linker doesn't know that.  In VC8 it will link the throwing version.  Linking with nothrownew.obj tells the linker that everything needs the old, non-standard version of new that returns NULL.

 

What if you are using 2 libs?  One that needs the non-standard new, and one that needs the standard new?  If that is the case, package one in it's own dll, or change it so you have consistency on the definition of new.  Don't bother trying to get the linker to do something magical.  It won't.  The linker makes a decision on what new means and that's it for the entire dll.

 

History of new through the VC's:

 

In VC5.0, and VC6.0 you basically got nothrow new and had to jump through hoops to get a throwing version.  MFC did use a throwing version, but it doesn't throw std::bad_alloc.  Also new(std::nothrow), had bugs which caused it to throw in some circumstances.  For users of non throwing new, life was good.  For everyone else, not so much. See this msdn article "Don't Let Memory Allocation Failures crash your lagacy STL Application" for the details.

 

In 7.0 and 7.1 the VC++ team attempted to do something clever.  The version of new you get is controlled by the first significant header in the first obj linked.  This means a large number of examples do exactly what you'd expect.  It also means there are corner cases where it is almost impossible to understand what's happening.  You could force a standard complying new by linking thrownew.obj.

 

In 8.0 the VC++ team decided to clean up many standard compliance issues.  Now the C++ standard is used.  Full Stop.  If you want the old behavior, you must link nothrownew.obj.

 

Finally, I must thank Martyn Lovell for explaining the background on this issue, and clarifying some of the details.  If there are any errors here they are due to me alone.

Comments

  • Anonymous
    November 10, 2005
    As far as I know VC does throw since many versions. It all depends on the new allocator. If an STL function reaches out of memory an bad_alloc exception is thrown. If you link to MFC a CMemoryException is thrown (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/core_Exception_Handling_Topics.28.MFC.29.asp). The only thing were no exception was thrown at all was if you did not link to MFC and if you do not use STL at all. I do not believe this changed behaviour will impact many applications. Normally you get this exception if you run out of address space (2GB) but not physical memory. This issue will go away when 64 Bit programs will become more and more. Then you will rarely need to check for a failed new. You will terminate the application anyway if the swap file is filling and the your application is slowed down a factor 1000 or more ;-)
  • Anonymous
    May 06, 2006
    It could be clearer in the documentation (and articles like this) that if you link against DLL MFC in 8.0, then the runtime still throws CMemoryException rather than std::bad_alloc. Is there a way to change that behaviour?
  • Anonymous
    January 15, 2008
    PingBack from http://msdn.blogsforu.com/msdn/?p=3840