In C++ How to program there is a paragraph that say:
A common programming practice is to allocate dynamic memory, assign the address of
that memory to a pointer, use the pointer to manipulate the memory and deallocate the
memory with delete when the memory is no longer needed. If an exception occurs after
successful memory allocation but before the delete statement executes, a memory leak
could occur. The C++ standard provides class template unique_ptr in header to
deal with this situation.
Any on could introduce me a real example that exception occur and memory will leak like this post?
class MyClass
{
public:
char* buffer;
MyClass(bool throwException)
{
buffer = new char[1024];
if(throwException)
throw std::runtime_error("MyClass::MyClass() failed");
}
~MyClass()
{
delete[] buffer;
}
};
int main()
{
// Memory leak, if an exception is thrown before a delete
MyClass* ptr = new MyClass(false);
throw std::runtime_error("<any error>");
delete ptr;
}
int main()
{
// Memory leak due to a missing call to MyClass()::~MyClass()
// in case MyClass()::MyClass() throws an exception.
MyClass instance = MyClass(true);
}
See also: C++ : handle resources if constructors may throw exceptions (Reference to FAQ 17.4]
A bit more subtle example.
Take an naive implementation of a class that holds two dynamically allocated arrays:
struct Foo {
private:
int* first;
int* second;
public:
Foo()
: first(new int[10000])
, second(new int[10000])
{ }
void Bar() { throw 42; }
~Foo()
{
delete [] first;
delete [] second;
}
};
int main()
{
Foo f;
/* more code */
}
Now, if we get an exception because we call method Bar
somewhere, everything's fine - the stack unwinding guarantess that f
's destructor gets called.
But if we get a bad_alloc
when initializing second
, we leak the memory that first
points to.
void func()
{
char *p = new char[10];
some_function_which_may_throw(p);
delete [] p;
}
If the call to some_function_which_may_throw(p)
throws an exception we leak the memory pointed to by p
.
Simple example
try {
int* pValue = new int();
if (someCondition) {
throw 42;
}
delete pValue;
} catch (int&) {
}
To have a less contrived example, I recently found this potential leak in my code when allocating nodes with a given allocator object.
std::unique_ptr<node,alloc_aware> allocate_new_node(allocator& al, const value_type^ v) {
char* buffer = al.allocate(sizeof(node)); //allocate memory
return std::unique_ptr<node>(al.construct(buffer, v),{al})); //construct
}
It's less obvious how to fix this because of the buffer, but with help I got it:
struct only_deallocate {
allocator* a;
size_type s;
only_deallocate(allocator& alloc, size_type size):a(&alloc), s(size) {}
template<class T> void operator()(T* ptr) {a->deallocate(ptr, s);}
operator alloc_aware() const {return alloc_aware(*a, s);}
};
std::unique_ptr<node,alloc_aware> allocate_new_node(allocator& al, const value_type& v) {
std::unique_ptr<node, only_deallocate> buf(alloc.allocate(sizeof(node)),{alloc, sizeof(node)});//allocate memory
alloc.construct(buf.get(), value);
return std::unique_ptr<node,alloc_aware>(std::move(buf));
}
Compiling Code here