How to free memory after exception in C ++?

I apologize if this question is a duplicate - I have been looking for some time, but it is possible that my Google-fu is simply not up to the tobacco.

I am changing a C ++ program that calls into a C library. The C library allocates a bunch of memory (using malloc() ), and the C ++ program uses it and then frees it. The trick is that a C ++ program can throw an exception halfway through execution, as a result of which the allocated memory will never be freed.

As an example (far-fetched):

 /* old_library.c */ char *allocate_lots() { char *mem = (char *)malloc(1024); return mem; } /* my_prog.cpp */ void my_class::my_func () { char *mem = allocate_lots(); bool problem = use(mem); if (problem) throw my_exception("Oh noes! This will be caught higher up"); free(mem); // Never gets called if problem is true } 

My question is: how do I deal with this? My first idea was to wrap it all in a try / catch block, and in catch just check and free the memory and throw the exception again, but that seems rude and clumsy to me (and won't work if I really want to catch an exception). Is there a better way to do this?

EDIT: I probably should have mentioned that we used g ++ 4.2.2 from 2007, before std :: unique_ptr was introduced. Chalk it to corporate inertia.

+6
source share
7 answers

Use std::unique_ptr with a custom uninstall that causes free:

 class free_mem { public: void operator()(char *mem) { free(mem); } }; void my_class::my_func() { std::unique_ptr<char, free_mem> mem = allocate_lots(); 
+7
source

You have to make sure that you do not drop until you free the memory, or that you use a suitable intelligent pointer structure to store mem , for example, when throw occurs and the stack goes offline, mem freed.

+4
source

Trick this villain:

 struct malloc_deleter { template <typename T> void operator () (T* p) const { free(p); } }; void my_class::my_func () { std::unique_ptr<char[],malloc_deleter> mem{allocate_lots()}; bool problem = use(mem.get()); if (problem) throw my_exception("Oh noes! This will be caught higher up"); } 
+4
source

Since you are using an old version of the compiler that does not have unique_ptr , you can write your own RAII wrapper yourself:

 class ResourceWrapper { public: ResourceWrapper(char* ptr) : m_ptr(ptr) {} ~ResourceWrapper() { free(m_ptr); } // whatever getters suit you, at the very least: char* get() const { return m_ptr; } private: char* const m_ptr; }; void my_class::my_func () { ResourceWrapper mem(allocate_lots()); bool problem = use(mem.get()); if (problem) throw my_exception("Oh noes! This will be caught higher up"); } 

Just make sure that it doesn’t even allow you to copy / assign implicitly (which is why I did m_ptr const), or you m_ptr risk of getting double memory deallocation (the semantics of "move" Γ  la auto_ptr best avoided if you do not need it).

+2
source

Since you cannot use std::unique_ptr , you can create your own deleter class that will manage the RAII-style pointer lifetime. To simplify this example, this example does not wrap the actual pointer, but exists next to it; a safer approach would be to create a true class of smart pointers.

 class AutoFree { public: AutoFree(void* p) : m_p(p) { } ~AutoFree() { free(m_p); } private: void* m_p; }; void my_class::my_func () { char *mem = allocate_lots(); AutoFree mem_free(mem); bool problem = use(mem); if (problem) throw my_exception("Oh noes! This will be caught higher up"); } 
+2
source

Is there a reason to not just free the memory inside the if clause?

 if (problem) { free (mem); throw my_exception ("Drat!"); } 
+1
source

Use unique_ptr: http://coliru.stacked-crooked.com/view?id=cd3f0fc64d99cc07a2350e2ff9686500-542192d2d8aca3c820c7acc656fa0c68

 #include <stdexcept> #include <iostream> #include <memory> /* old_library.c */ char *allocate_lots() { return static_cast<char*>(malloc(1024)); } struct my_exception : virtual std::exception { const char* const msg; my_exception(const char* const msg) : msg(msg) {} const char* what() const noexcept { return msg; } }; struct my_class { struct Free { void operator() (char* p) const { free(p); } }; /* my_prog.cpp */ void my_func() { std::unique_ptr<char, Free> mem; mem.reset(allocate_lots()); bool problem = use(mem.get()); if(problem) { throw my_exception("Oh noes! This will be caught higher up"); } } static bool use(char*) { return true; } }; int main() { my_class prog; prog.my_func(); } 
+1
source

Source: https://habr.com/ru/post/950583/


All Articles