Freigeben über


Avoid Manual Memory Management

 

This post is all about how to avoid freeing a memory block that is allocated by us manually. Attempting to free the allocations manually may result in memory leaks, access violations, unreadable code, and maintenance problems. For example, look at the below code piece:

image

Do you see the problem(s) here ? Anytime something goes wrong, we have to remember to delete the pointer. Otherwise memory will be leaked. What happens if someone else visits this code and modifies it in the future ? It’s very likely that another return path will be introduced and ptr won’t be freed. Even if all the delete operators are used correctly, an inner method may throw intentionally or unintentionally and leave the memory allocated in the process. One final problem is the readability of this code. We make it unnecessarily longer and hard to read by trying to handle all the delete operations. What would our function look like if it allocates multiple variables!

Here is another typical problem:

image

First, I am really against using raw pointers to allocate memory. Second, passing the raw pointer from one scope to another is something we should avoid. In some cases, multiple objects may want to share same memory block. For example, if you have an object dynamically created in the heap and if multiple objects want to consume this object, you start passing this object around..

To make our operations safer and cleaner we can use shared_ptr when we create the objects. shared_ptr holds a reference count to the object and frees it when the last reference goes away. Two popular shared_ptr classes are in the tr1 and boost library.

image

This is much better. We allocate a memory block for MyClass object by using a shared_ptr. So we don’t need to call delete operator on it; shared_ptr will automatically free it when the last reference goes out of scope. foo method’s input parameter is also a type of shared_ptr so when we pass the ptr object to the foo, it’s reference count will increment   by one preventing other shared_ptr objects freeing the MyClass object.

Sometimes, all we need to do is to create a buffer and use it in the same function and get rid of it quickly. In these cases, we can either use auto_ptr or a vector object.

auto_ptr is useful when we need to allocate a class object. For example; auto_ptr<MyClass> ptr = new MyClass();

When auto_ptr goes out of scope, it will delete the object automatically for us. Unlike shared_ptr, auto_ptr does not keep a reference count so you should not pass auto_ptrs around. This will very likely cause an access violation since each auto_ptr destructor will try to free the memory block.

vector object is useful when you want to allocate an array of primitive type variables. I generally use vector class to create string buffers or BYTE buffers. When object goes out of scope, it will again free the memory for us.  std::vector<wchar_t> buffer(size, L’\0’); creates a buffer of wchar_t in size length and fills the buffer with NULLs for us.

In conclusion, avoid using raw pointers and delete operator in your code. There are beautiful smart pointers and techniques to do memory management automatically.