Satview: Pointer Perfect, Part 3 - Functions
(Page 2 of 6 )
In any procedural programming language, you heavily rely on functions. Functions acquire resources, perform operations and then free the resources. Functions create resources on the stack when the function is being entered and might create resources there during its execution. As soon as we leave the function, the resources are thrown from the stack, destroying them.
A typical function could look like this:
void foo() {
MyClass *pMyObj = new MyClass;
/* perform some operations here */
delete pMyObj;
}
The most obvious problem with pointers is the possible misbalancing of new and delete (every allocated resource has to be freed to prevent memory leaks). In this example, you see the memory allocated being freed just before we exit the function. But is this the only way we can exit this function? An exception might be thrown in the body of this function, causing us to leave it without ever reaching the delete statement. If we want to avoid causing the resulting memory (or other resources like files) to leak, we need to catch all exceptions:
void foo() {
try {
MyClass *pMyObj = new MyClass;
/* perform some operations here */
}
catch (…) {
delete pMyObj;
throw; // rethrow the exception
}
delete pMyObj;
}
You will most probably have found yourself writing code like this and know that this structure only makes the code more complex and more difficult to maintain--especially when we want to handle different types of exceptions differently. Sometimes you might find solutions that don’t need to rethrow the exception employ the following solution:
void foo() {
MyClass *pMyObj = NULL;
try {
*pMyObj = new MyClass;
/* perform some operations here */
}
catch (std::exception const &ex) {
(void)printf(“Exception! %s\n”, ex.what());
goto cleanup;
}
catch (…) {
(void)printf(“Unknown exception!\n”);
goto cleanup;
}
cleapup:
delete pMyObj;
}
Still, the whole exception mechanism was invented to make sure the stack unwinds when an error is faced (offering constructed objects the possibility of properly destructing); all because the goto statement completely ignores this. Looking upon the code above, it becomes clear that this mixture of try/catch and goto is not the right way to handle possible resource leaks when exceptions are thrown.
Goto’s are bad and should never be used, unless you are 100% sure of what you are doing. This means that you are not jumping backwards and not out of a function; the goto label is nearby and there are no possible resource leaks when you jump.
Next: Smart pointers >>
More C# Articles
More By J. Nakamura