While going through Effective C++ (by Scott Meyers), I came across the following code that the author uses to illustrate how exceptions should be handled when copying data members from one object to another.
class Bitmap { ... };
class Widget {
...
private:
Bitmap *pb; // ptr to a heap-allocated object
};
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap *pOrig = pb; // remember original pb
pb = new Bitmap(*rhs.pb); // make pb point to a copy of *pb
delete pOrig; // delete the original pb
return *this;
}
In the event that “new Bitmap” throws an exception, pb will remain unchanged. However, by deleting
pOrig, the memory to which pb points has been freed. Isn’t this dangerous? How is it any better than the following code
Widget& Widget::operator=(const Widget& rhs)
{
if (this == &rhs) return *this; // identity test: if a self-assignment,
// do nothing
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
Which (he claims) is bad because when “new Bitmap” yields an exception (either because there is insufficient memory for the allocation or because Bitmap’s copy constructor throws one), the Widget will end up holding a pointer to a deleted Bitmap
I checked the book errata, but found no mention of this example. Am I missing something obvious? Also, can someone suggest a better way of handling this exception?
The
delete pOrig;will be executed if and only ifpb = new Bitmap(*rhs.pb);succeeds. If the allocation fails, then no more of this ctor will execute at all — instead, the stack will be unwound, and execution will go from whatever part of theBitmapconstructor threw the exception, directly to the handler for whatever exception was thrown. The only stop along the way will be destroying the variables local to the ctor, but since the only local variable is a pointer, destroying it is pretty much a nop.In the case that the Widget object contained any other member variables, any of those that had been completely constructed would also be destroyed as part of the stack unwinding, but since it doesn’t have any (shown) that’s irrelevant here.