All good C++ programmers know how to avoid leaking memory (or resources like sockets):
- Always use smart pointers, i. e.:
std::auto_ptr
, boost::shared_ptr
.
- Always be aware of ownership of object: who owns, who refers, who is responsible, etc.
But, memory leaks still happen. Point most common issues when you discovered
a memory leak in a program, even when you used the above techniques.
I start:
Sometimes you forget to define a destructor of base class as virtual. So all derived classes referred by pointer to the base class which was not destroyed properly and therefore leaked.
There are many more types of errors than just leaks. In order from worst to best:
Memory corruption.
Data is stored to an area where it shouldn't. This results in both the majority of security problems and is by far the hardest to track down.
- "Random location" corruption
- Data is stored to a memory location that the user can control.
- Data is stored to an array without checking the indices.
- An object of a type derived from
X
is stored to an array element reserved for a base type of X
, and the size of X
is greater than the size of its base.
- Lifetime corruption
- Data is store to a memory location after it is freed.
- Incorrect method of freeing is used (mismatch resulting in
new
/free
, malloc
/delete
)
delete
or free
is called twice on the same pointer.
Failure to release memory
Memory no longer in use by the program remains allocated.
- Incorrect method of freeing is used: mismatch resulting in
new[]
/delete
instead of new[]
/delete[]
.
- Memory is not automatically release because of a circular reference in a reference counting scheme, such as can happen when
smart_ptr
is used in a circular data structure without attention to using weak_ptr
for the circular link.
- Memory is not freed due to a lost pointer - the last pointer to the memory was cleared before free was called, so there is no way to release it.
- Memory is not freed due to not properly identifying when the data it contains is no longer needed. An example is a static cache used for some temporary task is never cleared out.
Circular references are common, and they aren't solved by std::auto_ptr
or boost::shared_ptr
There is no substitute for (2) on your list, which is using your brain.
A mistake made by people too familiar with automatic garbage collection (through smartpointers):
class A {
public:
int avery_useful_calculation()const { return 4; }
private:
// class shouldn't be instantiated as an automatic variable (on stack)
virtual ~A(){}
};
// client code: needs a very useful calculation
int i = (new A)->avery_useful_calculation();
Maybe I am out of scope, but I had some strange errors trying to "delete" uninitialized pointers.
To "avoid" memory leakage, I use the try {} __finally {}
structure if implemented (but I read somewhere it may be inefficient if an exception was raised in a sub-sub-call)