6

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?

Community
  • 1
  • 1
Milad Khajavi
  • 2,769
  • 9
  • 41
  • 66
  • Does this answer your question? [How to create a memory leak in C++?](https://stackoverflow.com/questions/7242493/how-to-create-a-memory-leak-in-c) – Sapphire_Brick May 04 '20 at 01:07
  • None of the answers in the duplicate show how to create a memory leak in C++ with the use of an exception. The answers here do that. The duplicate flag/closure should be removed. – 9769953 Jul 04 '22 at 12:22

5 Answers5

13

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.

jrok
  • 54,456
  • 9
  • 109
  • 141
7
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]

Community
  • 1
  • 1
Sam
  • 7,778
  • 1
  • 23
  • 49
  • -1. `MyClass* ptr = new MyClass(true);` won't leak if the constructor throws an exception. – Mooing Duck Mar 12 '13 at 21:40
  • heh, removed the -1, but now the `new` and `delete` in the last sample are misleading. Also, `new` and `malloc` in the same program? – Mooing Duck Mar 12 '13 at 21:46
  • 1
    Not anymore :). Thanks for voting AND commenting! – Sam Mar 12 '13 at 21:48
  • @Sam: no, I mean the last sample could very well be `int main() {MyClass A;}` and the memory leak would _still_ occur. The leak is in `MyClass`, not in that function. – Mooing Duck Mar 12 '13 at 22:50
  • Creating proper memory leak examples is actually harder than expected xD – Sam Mar 12 '13 at 22:59
  • Don't you need a try catch block and some more code (...) or don't use main() to make a real memory leak example? Here the execution ends at the exception so no memory is leaked. Even if caught, it is in main() so it exits. – user1122069 Mar 26 '17 at 03:52
  • @user1122069: I see your point. Things look different depending on the resource scopes of the platform one is looking at. That memory block is unreachable in main(), making this example a leak from a code perspective, regardless of how many times it is called or (explicit) catch blocks and subsequent code. That means, the process would exit with unreachable, still allocated memory (visible with valgrind memcheck, etc.). On platforms which don't manage resources for individual processes/tasks, the system would have to deal with 'lost' memory blocks until it is reinitialized one way or another. – Sam Mar 27 '17 at 09:22
6
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.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
3

Simple example

try { 
  int* pValue = new int();
  if (someCondition) { 
    throw 42;
  }
  delete pValue;
} catch (int&) { 

}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

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

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158