- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
-
Tips and Techniques
- Using the Swap() Algorithm
- Using class stopwatch for Performance Measurements
- Extending <tt><iostream></tt> to Support User-Defined Types
- Using <tt>auto_ptr</tt> To Automate Memory Management
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part II
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part III
- Using <tt>enum</tt>s as Mnemonic Indexes
- Create Objects on Pre-Allocated Memory Using <tt>Placement-new</tt>
- Online Books: <tt>Placement-new</tt>
- Bitwise Operators
- Bitwise Operators II
- Who's <tt>this</tt>?
- A Reference Guide
- The Virtues of Multiple Inheritance
- Interfaces
- Multiple Inheritance: Construction and Destruction Order
- nothrow new
- POD Initialization
- Object Initialization
- <tt>const</tt> Declarations
- The Semantics of <tt>volatile</tt>
- <tt>inline</tt> Functions
- Project Organization Guidelines
- All About <tt>bool</tt>
- <tt>typedef</tt> Declarations
- State of the <tt>union</tt>
- Dynamic Cast Uses
- Integrating C and C++
- <tt>const</tt>-Correctness
- <tt>const</tt>-Correctness: Advanced Issues
- Sprucing Up Legacy Code
- Virtual Constructors
- Naming Names
- Function Calls
- Speaking Standardese (updated)
- Speaking Standardese: the One Definition Rule
- Declarations and Definitions
- More on Declarations and Definitions
- The Most Vexing Parse
- Finally, At Last
- Sound Bytes (Admittedly Off Topic)
- Local Classes
- Complex Arithmetic
- Floating Point Woes
- String Manipulation
- The Object Model
- The Object Model II
- The Object Model III
- Temporary Objects
- Temporary Objects: Advanced Techniques
- Over-Engineering
- Security Enhancements
- Drop the (automatic) Pilot
- Choosing the Right Container
- Choosing the Right Container II
- Choosing the Right Container, Part III
- Arrays and Pointers
- Low-Level File I/O
- Low-Level File I/O Part II
- static Declarations, Part I
- static Declarations, Part II
- <code>static</code> Initialization Order
- Revisiting the Deprecation of File-Scope Static
- Virtual Memory and Memory Mapping
- Cellular Phone Programming Guidelines
- The Handle/Body Idiom
- Whole Program Optimization, Part I
- Whole Program Optimization, Part II
- Manipulating Directories
- Window Dressing
- <code>friend</code> Declarations
- <code>friend</code> Part II: the Interaction of Friendship and Template Classes
- Forcing Object Allocation on Specific Storage Types
- Lazy Evaluation
- Cache and Carry
- Controlling a Container’s Capacity
- Non-Blocking I/O, Part I
- Non-Blocking I/O, Part II
- Using Unions for Automatic Conversion
- Launching a Child Process
- <tt>switch</tt> Statements
- Introducing the "struct Hack"
- Scoped Enumerators
- Doing Statistics with STL
- Fixing the "Unresolved External" Linkage Error
- Understanding Calling Conventions
- Understanding the Empty Base Optimization
- Implementing RPC with the door Library, Part 1
- Implementing RPC with the door Library, Part 2
- Eliminating Two Common Pointer and <tt>sizeof</tt> Bugs
- Command Line Arguments
- Performance Myths Busting
- Tag Names And Types Part I
- Tag Names And Types Part II
- The Infamous goto
- Trimming Strings
- Can Objects Live Forever? Part I
- Can Objects Live Forever? Part II
- Five Ways to Improve Your Functions
- Member Aggregate Initialization
- Five Futile Coding-Style Debates
- The Good Parasite Idiom: An Exercise in OOD
- The Good Parasite Idiom: An Exercise in OOD, Part II
- The Good Parasite Idiom: An Exercise in OOD, Part III
- Ten Techniques to Reduce the Size of Your Classes, Part I
- Ten Techniques to Reduce the Size of Your Classes, Part II: Inheritance Issues
- Ten Techniques to Reduce the Size of Your Classes, Part III
- Ten Techniques to Reduce the Size of Your Classes IV
- Taking the Address of an Object with an Overloaded Operator <tt>&</tt>
- strcpy() -- How and Why Does It "Just Work"?
- Anonymous Structs
- Five Easy Ways to Reduce The Size of your Executables
- Standard Layout Classes and Trivially Copyable Types, Part I
- Standard Layout Classes and Trivially Copyable Types, Part II
- Five Simple Code Sanity Checks
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
nothrow new
Last updated Jan 1, 2003.
I've already discussed several flavors of operator new, including the ordinary versions of new and placement new. Standard C++ has another version of this operator, called nothrow new. In the following sections I will describe its raison d'être and usage.
A Bit of History
Until the early 1990s, operator new behaved very much like standard C's malloc(), as far as allocation failures were concerned. When it failed to allocated a memory block of the requested size, it would return a NULL pointer. In those days, a typical new expression would look like this:
//pre-standard C++
CWindow * p;
p = new DerivedWind;
if (!p) //NULL indicates a failure
{
cout<<"allocation failure!"
exit(1);
}
//...continue normally
Programs had to check the pointer returned from new to verify that the allocation was successful; a pointer with a non-zero value indicated success.
This behavior was changed in the early 1990s. Instead of returning a NULL pointer, new throws an exception to indicate a failure. Because exceptions were rather new at that time, and because legacy code that relied on the original new behavior was still widely used, vendors were rather slow in adopting this change. Today, however, most existing compilers implement new in a standard-compliant manner.
Standard Compliant new
Let's examine the behavior of standard-compliant new more carefully. As previously said, operator new throws an exception of type std::bad_alloc in case of failure. This means that testing the return value like this is utterly wrong:
p = new DerivedWind;
if (!p) //not to be used under ISO compliant compilers
{
cout<<"allocation failure!"
exit(1);
}
There are several problems with this code. The if condition is never evaluated in the event of an allocation failure, because the exception thrown by new has already transferred control to a matching catch() clause, if one exists. If no matching handler is found, C++ automatically calls function terminate() that terminates the program unconditionally.
Unfortunately, quite a few programmers still use this coding practice even today, not knowing how dangerous and erroneous it is. A standard compliant version of this code should look like this:
try
{
p = new DerivedWind;
}
catch (std::bad_alloc &ba)
{
cout<<"allocation failure!"
//...additional cleanup
}
There are, however, certain cases in which the pre-standard behavior of new is needed. For example, embedded systems don't always support exceptions. In such environments, nothrow new can be rather useful.
nothrow new's Interface
The standard header file <new> defines a struct called std::nothrow_t like this:
struct nothrow_t {}; //defined in namespace std
This empty struct merely serves as a policy enforcing parameter in the following overloaded versions of new:
//declarations appear in <new> void* operator new (size_t size, const std::nothrow_t &); void* operator new[] (void *v, const std::nothrow_t &nt);
<new> also defines a global object of type std::notrow_t:
extern const nothrow_t nothrow;
The definition of a global object enables all C++ programs to use nothrow new uniformly, by using the same argument name.
Putting nothrow new to Work
By using nothrow new one can easily make the previous code listing standard compliant, while retaining its original structure and semantics:
//standard C++ code
#include <new> //required for nothrow new
CWindow p;
p = new(std::nothrow) DerivedWind;
if (!p) //fine now
{
cout<<"allocation failure!"
exit(1);
}
//...continue normally
Notice that no changes were made to the original code, save the new(nothrow) expression. If you want to test the behavior of this code fragment in case of an allocation failure, try to allocate a huge amount of memory:
//force an allocation failure to test
//the behavior of nothrow new
p = new(std:::nothrow) DerivedWind[1000000000];
if (!p)
{
cout<<"allocation failure!"
exit(1);
}
Summary
The existence of nothrow new exemplifies the constant conflicts that C++ creators have faced during its 20 years of existence. On the one hand, they've attempted to ensure that existing code wouldn't break due to changes in the core language. On the other hand, they haven't avoided necessary extensions and modifications.
That said, nothrow new isn't necessarily a transitory feature. As stated previously, C++ is used in resource constrained environments in which exceptions aren't supported. Such environments necessitate the use nothrow new in new code as well.
