This is an exercise from C++ Primer, chapter 18:
void exercise(int *b, int *e)
{
vector<int> v(b, e);
int *p = new int[v.size()];
ifstream in("ints");
// exception occurs here
}
The code above would cause memory leak, because the memory we manage directly (i.e. p
) is not automatically freed when an exception occurs.
Exercise 18.3:
There are two ways to make the previous code work correctly if an exception is thrown. Describe them and implement them.
I know we can use smart pointer to avoid this pitfall:
void exercise(int *b, int *e)
{
vector<int> v(b, e);
unique_ptr<int[]> p(new int[v.size()]);
ifstream in("ints");
// exception occurs here
}
or:
void exercise(int *b, int *e)
{
vector<int> v(b, e);
shared_ptr<int> p(new int[v.size()], [](int *p){ delete[] p; });
ifstream in("ints");
// exception occurs here
}
I'm not sure if these are TWO
ways. After all, they are the same virtually. So I thought of another way:
void exercise(int *b, int *e)
{
vector<int> v(b, e);
int *p = new int[v.size()];
ifstream in("ints");
// exception occurs here
if(!in)
throw p;
}
// caller
try {
exercise(b, e);
} catch (int *err) {
delete[] err; // initialize err with b and delete e.
}
If exception occurs, throw p
to initialize another pointer and delete that one. I know this is not a perfect solution, because other exceptions might occur so that I don't even have a chance to throw p
. But I can't think of a better one. Could you help to find the second way?
By wrapping around the code and avoiding using "naked" resources, everything is based on the stack and the fact that those resources are going to be released for sure if an exception occurs.
In summary, to avoid context-related memory leaks, remember the following: Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself) Try using the context-application instead of a context-activity.
The pointer to the object goes out of scope when the exception leaves the function, and the memory occupied by the object will never be recovered as long as the program is running. This is a memory leak; it would be detected by using the memory diagnostics.
You can explicitly catch and re-throw the exception:
void exercise(int *b, int *e)
{
vector<int> v(b, e);
int *p = new int[v.size()];
try {
ifstream in("ints");
// exception occurs here
} catch (...) {
delete[] p;
throw;
}
delete[] p;
}
Of course this doesn't work so well if you have multiple resources to free, because you may end up with nested try/catch blocks. Not to mention that you have two delete
s for one new
. So RAII is preferred.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With