Online Book Reader

Home Category

Professional C__ - Marc Gregoire [171]

By Root 1416 0
old.

new_handler oldHandler = set_new_handler(myNewHandler);

// Generate allocation error

int numInts = numeric_limits::max();

int* ptr = new int[numInts];

// reset the old new_handler

set_new_handler(oldHandler);

} catch (const PleaseTerminateMe&) {

cerr << __FILE__ << "(" << __LINE__

<< "): Terminating program." << endl;

return 1;

}

return 0;

}

Code snippet from NewFailures\NewHandler.cpp

Note that new_handler is a typedef for the type of function pointer that set_new_handler() takes.

Errors in Constructors

Before C++ programmers discover exceptions, they are often stymied by error handling and constructors. What if a constructor fails to construct the object properly? Constructors don’t have a return value, so the standard pre-exception error-handling mechanism doesn’t work. Without exceptions, the best you can do is to set a flag in the object specifying that it is not constructed properly. You can provide a method, with a name like checkConstructionStatus(), which returns the value of that flag, and hope that clients remember to call the function on the object after constructing it.

Exceptions provide a much better solution. You can throw an exception from a constructor, even though you can’t return a value. With exceptions you can easily tell clients whether or not construction of the object succeeded. However, there is one major problem: if an exception leaves a constructor, the destructor for that object will never be called. Thus, you must be careful to clean up any resources and free any allocated memory in constructors before allowing exceptions to leave the constructor. This problem is the same as in any other function, but it is subtler in constructors because you’re accustomed to letting the destructors take care of the memory deallocation and resource freeing.

This section describes a Matrix class as an example in which the constructor correctly handles exceptions. The definition of the Matrix class looks as follows:

#include

#include "Element.h"

class Matrix

{

public:

Matrix(unsigned int width, unsigned int height) throw(std::bad_alloc);

virtual ~Matrix();

protected:

unsigned int mWidth;

unsigned int mHeight;

Element** mMatrix;

};

Code snippet from ConstructorError\Matrix.h

The preceding class uses the Element class, which is kept at a bare minimum for this example:

class Element

{

protected:

int mValue;

};

Code snippet from ConstructorError\Element.h

The implementation of the Matrix class is as follows. Note that the first call to new is not protected with a try/catch block. It doesn’t matter if the first new throws an exception because the constructor hasn’t allocated anything else yet that needs freeing. If any of the subsequent new calls throw exceptions, though, the constructor must clean up all of the memory already allocated. However, it doesn’t know what exceptions the Element constructors themselves might throw, so it catches any exception via ... and translates them into a bad_alloc exception. It is also important to have index i outside the try block because this index is needed during cleanup in the catch block.

Matrix::Matrix(unsigned int width, unsigned int height) throw(bad_alloc)

: mWidth(width), mHeight(height), mMatrix(nullptr)

{

mMatrix = new Element*[width];

unsigned int i = 0;

try {

for (i = 0; i < height; ++i)

mMatrix[i] = new Element[height];

} catch (...) {

cout << "Exception caught in constructor, cleaning up..." << endl;

// Clean up any memory we already allocated, because the destructor

// will never be called. The upper bound of the for loop is the

// index of the last element in the mMatrix array that we tried

// to allocate (the one that failed). All indices before that

// one store pointers to allocated memory that must be freed.

for (unsigned int j = 0; j < i; j++) {

delete [] mMatrix[j];

}

delete [] mMatrix;

mMatrix = nullptr;

// Translate any exception to bad_alloc.

throw bad_alloc();

}

}

Matrix::~Matrix()

{

for (unsigned int i = 0; i < mHeight; ++i)

delete [] mMatrix[i];

delete []

Return Main Page Previous Page Next Page

®Online Book Reader