views:

661

answers:

14

I was recently interviewing for a C++ position, and I was asked how I guard against creating memory leaks. I know I didn't give a satisfactory answer to that question, so I'm throwing it to you guys. What are the best ways to guard against memory leaks?

Thanks!

+1  A: 

Use all kind of smart pointers.

Use certain strategy for creation and deletion of objects, like who creates that is responsible for delete.

Mykola Golubyev
+6  A: 

replace new with shared_ptr's. Basically RAII. make code exception safe. Use the stl everywhere possible. If you use reference counting pointers make sure that they don't form cycles. SCOPED_EXIT from boost is also very useful.

Chris H
Please illustrate how you would replace 'new' with a shared pointer.
anon
boost::shared_ptr<T> ptr = boost::shared_ptr<T>(new T());
Chris H
That uses new - hardly replacing anything.
anon
I'd say that boost::shared_ptr<T> ptr(new T); would do the same but save a temp object creation and copy
davka
don't nit pick.
Chris H
do rephrase your answer
anon
+2  A: 

I start by reading the following: http://stackoverflow.com/search?q=%5Bc%2B%2B%5D+memory+leak

S.Lott
+1 for the typing effort ;)
neuro
+1  A: 

A very good way is using Smart Pointers, the boost/tr1::shared_ptr. The memory will be free'd, once the (stack allocated) smart pointer goes out of scope.

DerKuchen
A: 
  • Smart pointers.
  • Memory management.
  • Override 'new' and 'delete' or use your own macros/templates.
acron
+4  A: 
  1. (Easy) Never ever let a raw pointer own a object (search your code for the regexp "\= *new". Use *shared_ptr* or *scoped_ptr* instead, or even better, use real variables instead of pointers as often as you can.

  2. (Hard) Make sure you don't have any circular references, with shared_ptrs pointing to each other, use *weak_ptr* to break them.

Done!

Viktor Sehr
+1 for circualr references being an issue
jk
+21  A: 
  1. Don't allocate memory on the heap if you don't need to. Most work can be done on the stack, so you should only do heap memory allocations when you absolutely need to.

  2. If you need a heap-allocated object that is owned by a single other object then use std::auto_ptr.

  3. Use standard containers, or containers from Boost instead of inventing your own.

  4. If you have an object that is referred to by several other objects and is owned by no single one in particular then use either std::tr1::shared_ptr or std::tr1::weak_ptr -- whichever suits your use case.

  5. If none of these things match your use case then maybe use delete. If you do end up having to manually manage memory then just use memory leak detection tools to make sure that you aren't leaking anything (and of course, just be careful). You shouldn't ever really get to this point though.

Peter Alexander
-1 People who write thier own containers knows what theyre doing and doesnt need to be told not to use them for memory leak causes.
Viktor Sehr
@Viktor: No, plenty of people write their own containers without knowing what they're doing. The fact that a small minority of C++ programmers is able to write containers correctly doesn't mean that the vast majority won't benefit from being told to stop and use the standard ones.
jalf
`std::auto_ptr` is being deprecated. Use `std::unique_ptr` instead.
Adrian McCarthy
I don't see why these high level tools are better then new/delete with some thinking before writing the code, planning your objects and interactions. I've used valgrind in some of my schools projects and I guess the more I use new/delete, the more I get cautious not to make mistakes by forgetting to free some memory.Boost is definitely great, but I don't think I should rely on it to free MY memory. If I were such a programmer who couldn't manage his own memory, I'd go for Java or something else with a built-in garbage collector.Sorry if I was offensive. But that's how I see C++.
Spidey
@Spidey, then you see C++ differently than the luminaries and leaders of the field who have clearly come down on the side of RAII (and hence stack-allocation or using smart pointers).
Barry Wark
@Spidey: Do you use exceptions in your code? It is all but impossible to write exception-safe code with manual pairing of new and delete.
Nemanja Trifunovic
@Adrian: `unique_ptr` doesn't exist in the current C++ standard though. @Spidey: No programmer can "manage his own memory" in a non-trivial C++ program, without exploiting RAII. Of course, RAII is much more than smart pointers, a point often forgotten. If you simply mean that smart pointers aren't the holy grail, you're right. But "raw" delete calls are wrong on every level. The way sane C++ programmers "manage their memory" is by making sure objects are released automatically *when they're supposed to*. that's not quite the same as making everything ref-counted with `shared_ptr`
jalf
@Spidey. This has nothing to do with whether or not programmers "can" manage their own memory. The reason we use smart pointers is because (a) it makes things easier to type, and (b) we can focus on solving the problem at hand rather than writing `delete xyz` in every one of our destructors.
Peter Alexander
@Spidey: GC has its place that is for sure. But it is a blunt sledge hammer approach to memory management in comparison to the scalpes provided by C++. Yes it takes more skill to use a scalpe than a sledge hammer but the finer grain control is worth the effort (unlike C's flint based scalpes). Also note that with RAII (ie manually using new/delete) is a resapay for disaster as there is no safety in the presence of exceptions.
Martin York
@Jalf: I don't agree, and the reason is, adding to what I said, people smart enough when the built in containers doesn't fulfill thier needs don't write leaky containers.
Viktor Sehr
@Viktor: Yes, but I'm not talking about people smart enough to know when the built-in containers don't fulfill their needs. I'm talking about the far more numerous group of programmers who just *blindly* roll their own containers because they don't know about/don't understand the STL ones, or because they suffer from not-invented-here syndrome and don't trust standard library code to be correct and/or performant. The flaw in your argument is that you assume that only qualified programmers write new container classes.
jalf
@Jalf Then we have different perception of the world. I've never seen anyone not understanding the stl containers even thinking about writing thier own container (inherit them - maybe). The moment you start even considering what datastructurs lies beneth the containers, you learn the stl containers.
Viktor Sehr
@Viktor: Really? Every single beginning C++ programmer writes his own linked list or array wrapper. Everyone.
jalf
I guess I need to study design patterns and the STL/boost then. Thank you all for the comments.
Spidey
@jalf: of course we do, after all we are told to in the introductory courses of computer science... If only they could also introduce good habits and the STL...
Matthieu M.
A: 

On x86 you can regularly use Valgrind to check your code

clooky
+8  A: 

You'd do well to read up on RAII.

ScaryAardvark
+2  A: 
  • make sure that you understand exactly how an object will be deleted everytime you create one
  • make sure you understand who owns the pointer every time one is returned to you
  • make sure your error paths dispose of objects you have created appropriately
  • be paranoid about the above
doron
+18  A: 

What all the answers given so far boil down to is this: avoid having to call delete.

Any time the programmer has to call delete, you have a potential memory leak. Instead, make the delete call happen automatically. C++ guarantees that local objects have their destructors called when they go out of scope. Use that guarantee to ensure your memory allocations are automatically deleted.

At its most general, this technique means that every memory allocation should be wrapped inside a simple class, whose constructor allocates the necessary memory, and destructor releases it.

Because this is such a commonly-used and widely applicable technique, smart pointer classes have been created that reduce the amount of boilerplate code. Rather than allocating memory, their constructors take a pointer to the memory allocation already made, and stores that. When the smart pointer goes out of scope, it is able to delete the allocation.

Of course, depending on usage, different semantics may be called for. Do you just need the simple case, where the allocation should last exactly as long as the wrapper class lives? Then use boost::scoped_ptr or, if you can't use boost, std::auto_ptr. Do you have an unknown number of objects referencing the allocation with no knowledge of how long each of them will live? Then the reference-counted boost::shared_ptr is a good solution.

But you don't have to use smart pointers. The standard library containers do the trick too. They internally allocate the memory required to store copies of the objects you put into them, and they release the memory again when they're deleted. So the user doesn't have to call either new or delete.

There are countless variations of this technique, changing whose responsibility it is to create the initial memory allocation, or when the deallocation should be performed.

But what they all have in common is the answer to your question: The RAII idiom: Resource Acquisition Is Initialization. Memory allocations are a kind of resource. Resources should be acquired when an object is initialized, and released by the object itslef, when it is destroyed.

Make the C++ scope and lifetime rules do your work for you. Never ever call delete outside of a RAII object, whether it is a container class, a smart pointer or some ad-hoc wrapper for a single allocation. Let the object handle the resource assigned to it.

If all delete calls happen automatically, there's no way you can forget them. And then there's no way you can leak memory.

jalf
+1 - As George C. would say: What else ?
paercebal
Note that it could lead to awkward interview sessions with humourless interviewers : "How do you avoid memory leaks ?" ... "Avoid writing delete !"...
paercebal
all the more reason to say it ;)
jalf
-1 Yes there still are ways to get memory leaks; circular dependencies.
Viktor Sehr
@Viktor: Yes, incorrect code will still be incorrect. Perhaps you can show me a technique which solves *that* problem?
jalf
@Viktor: you are assuming that RAII==reference counting. That is not the case. How do circular dependencies prevent my `scoped_ptr` from deleting the object it points to. Reference counting (and `shared_ptr`) is *one* special case of RAII, and it has some crucial weaknesses, and it is way overused. But that doesn't change what I said, that RAII *in general* is the way to avoid leaks.
jalf
+2  A: 

In addition to the advice about RAII, remember to make your base class destructor virtual if there are any virtual functions.

Chris Card
+1 for the virtuality
neuro
+1  A: 

To avoid memory leaks, what you must do is to have a clear and definite notion of who is responsible for deleting any dynamically allocated object.

C++ allows construction of objects on the stack (i.e. as kind-of local variables). This binds creation and destruction the the control flow: an objects is created when program execution reaches its declaration, and the object is destroyed when execution escapes the block in which that declaration was made. Whenever allocation need matches that pattern, then use it. This will save you much of the trouble.

For other usages, if you can define and document a clear notion of responsibility, then this may work fine. For instance, you have a method or a function which returns a pointer to a newly allocated object, and you document that the caller becomes responsible for ultimately deleting that instance. Clear documentation coupled with good programmer discipline (something which is not easily achieved !) can solve many remaining problems of memory management.

In some situations, including undisciplined programmers and complex data structures, you may have to resort to more advanced techniques, such as reference counting. Each object is awarded a "counter" which is the number of other variables which point to it. Whenever a piece of code decides to no longer point to the object, the counter is decreased. When the counter reaches zero, the object is deleted. Reference counting requires strict counter handling. This can be done with so-called "smart pointers": these are object which are functionally pointers, but which automatically adjust the counter upon their own creation and destruction.

Reference counting works quite good in many situations, but they cannot handle cyclic structures. So for the most complex situations, you have to resort to the heavy artillery, i.e. a garbage collector. The one I link to is the GC for C and C++ written by Hans Boehm, and it has been used in some rather big projects (e.g. Inkscape). The point of a garbage collector is to maintain a global view on the complete memory space, to know whether a given instance is still in use or not. This is the right tool when local-view tools, such as reference counting, are not enough. One could argue that, at that point, one should ask oneself whether C++ is the right language for the problem at hand. Garbage collection works best when the language is cooperative (this unlocks a host of optimizations which are not doable when the compiler is unaware of what happens with memory, as a typical C or C++ compiler).

Note that none of the techniques described above allows the programmer to stop thinking. Even a GC can suffer from memory leaks, because it uses reachability as an approximation of future usage (there are theoretical reasons which imply that it is not possible, in full generality, to accurately detect all objects which will not be used thereafter). You may still have to set some fields to NULL to inform the GC that you will no longer access an object through a given variable.

Thomas Pornin
A: 

You can get free ideal smart pointer implementation at:

www.gnotum.com

Download it and forget about delete operator and memory leaks

irakl