What Happens If new Fails?

Section 21.4

Every book on C++ has a section on handling new failures. The accepted wisdom for how to handle such failures tends to vary, because the behavior of a C++ program when it runs out of memory is not the same from one platform to another.

We begin our discussion with a caveat. When a C++ program has a memory leak and runs for a long time, eventually there will be no memory available to it. You might think that would cause an exception to be thrown. However most modern operating systems (including *nix and Win32) implement virtual memory, which permits the operating system, when its random access memory (RAM) fills up beyond some preset level, to copy the contents of memory that has not been used recently to a special place on the system disk drive. This substitution of relatively slow memory (disk storage) for fast memory (RAM) is generally invisible to the user (except for the performance degradation). If the demands on the system RAM are especially heavy, the OS will use virtual memory to keep satisfying allocation requests until the system starts thrashing.[3] When this happens, the whole system grinds to a halt until the system administrator can intervene and kill the memory-eating process. At no point will any of the memory allocation failure-handling code be reached in the errant process. It is for this reason that memory allocation errors are handled differently, or not at all, in various applications.

[3] When a system is constantly swapping memory back and forth to disk, preventing other I/O from happening, we call that "thrashing."

Having said this, the ANSI/ISO standard does specify that the free store operator new should throw a bad_alloc exception instead of returning NULL if it cannot carry out an allocation request. If a thrown bad_alloc exception is not caught by a catch() block, the default exception handler is called, which could be either abort() or terminate().

Example 22.7 demonstrates this feature of C++.

Example 22.7. src/newfailure/bad-alloc1.cpp

#include 
#include 
using namespace std;

void memoryEater() {
 int i = 0;
 double* ptr;
 try {
 while(1) {
 ptr = new double[50000000];
 cerr << ++i << '	' ;
 }

 } catch (bad_alloc& excpt) {
 cerr << "
Exception occurred: "
 << excpt.what() << endl;
 }
}

int main() {
 memoryEater(); <-- 1
 cout << "Done!" << endl;
 return 0;
}

Output:

src/newfailure> g++ bad-alloc1.cpp
src/newfailure> ./a.out
1 2 3 4 5 6 7
Exception occurred: St9bad_alloc
Done!
src/newfailure>
 

(1)Try to use up the memory.

22.9.1. set_new_handler(): Another Approach to New Failures

We can specify what new should do when there is not enough memory to satisfy an allocation request. When new fails, it first calls the function specified by set_new_handler(). If new_handler has not been set, a bad_alloc object is thrown that can be queried, as shown in Example 22.7, for more information by calling one of its member functions. Example 22.8 shows how to specify our own new_handler.

Example 22.8. src/newfailure/setnewhandler.cpp

#include 
#include 
#include 
using namespace std;

void memoryEater() {
 int i = 0;
 double* ptr;
 while(1) {
 ptr = new double[50000000];
 cerr << ++i << '	' ;
 }
}

void out_of_store() {
 cerr << "
operator new failed: out of store
";
 exit(1);
}

int main() {
 set_new_handler(out_of_store);
 memoryEater();
 cout << "Done!" << endl;
 return 0;
}

Output:

src/newfailure> g++ setnewhandler.cpp
src/newfailure> ./a.out
1 2 3 4 5 6 7
operator new failed: out of store
OOP>

Note the absence of a TRy block.

Exercise: set_new_handler()Another Approach to new Failures

 

What happens if the last command in the out_of_store() function is not exit()?

22.9.2. Using set_new_handler and bad_alloc

Example 22.9 throws a standard exception from the new_handler.

Example 22.9. src/newfailure/bad-alloc2.cpp

#include 
#include 
#include 
using namespace std;

void memoryEater() {
 int i = 0;
 double* ptr;
 try {
 while(1) {
 ptr = new double[50000000];
 cerr << ++i << '	' ;
 }

 } catch(bad_alloc& excpt) {
 cerr << "
Exception occurred: "
 << excpt.what() << endl;
 }
}

void out_of_store() {
 cerr << "
operator new failed: out of store
";
 throw bad_alloc();
}

int main() {
 set_new_handler(out_of_store);
 memoryEater();
 cout << "Done!" << endl;
 return 0;
}

Output:

src/newfailure> g++ bad-alloc2.cpp
src/newfailure> ./a.out
1 2 3 4 5 6 7
operator new failed: out of store

Exception occurred: St9bad_alloc
Done!
src/newfailure>

22.9.3. Checking for null: The Updated Way to Test for New Failures

You may encounter the old null-checking style for detecting failures of new in legacy code. That's a sure sign that there are going to be problems with maintenance. Fortunately, there is a simple way to update that old approach.

In Example 22.10, we add the qualifier (nothrow) to the allocation statement. As its name suggests, this qualifier suppresses the throwing of bad_alloc and allows new to return a 0 pointer if it fails.

Example 22.10. src/newfailure/nullchecking.cpp

#include 
#include 
using namespace std;

void memoryEater() {
 int i = 0;
 double* ptr;
 while(1) {
 ptr = new (nothrow) double[50000000];
 if (ptr == 0)
 return;
 cerr << ++i << '	' ;
 }
}

int main() {
 memoryEater();
 cout << "Done!" << endl;
 return 0;
}

Output:

src/newfailure> g++ nullchecking.cpp
src/newfailure> ./a.out
1 2 3 4 5 6 7 Done!
src/newfailure>


Part I: Introduction to C++ and Qt 4

C++ Introduction

Classes

Introduction to Qt

Lists

Functions

Inheritance and Polymorphism

Part II: Higher-Level Programming

Libraries

Introduction to Design Patterns

QObject

Generics and Containers

Qt GUI Widgets

Concurrency

Validation and Regular Expressions

Parsing XML

Meta Objects, Properties, and Reflective Programming

More Design Patterns

Models and Views

Qt SQL Classes

Part III: C++ Language Reference

Types and Expressions

Scope and Storage Class

Statements and Control Structures

Memory Access

Chapter Summary

Inheritance in Detail

Miscellaneous Topics

Part IV: Programming Assignments

MP3 Jukebox Assignments

Part V: Appendices

MP3 Jukebox Assignments

Bibliography

MP3 Jukebox Assignments



An Introduction to Design Patterns in C++ with Qt 4
An Introduction to Design Patterns in C++ with Qt 4
ISBN: 0131879057
EAN: 2147483647
Year: 2004
Pages: 268

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net