Luc Aux
Luc Aux

Reputation: 189

How to confirm you are not having memory leaks?

So..I am trying to write my first destructor. I have sth, but I don't know if it is actually doing what it supposed to do.

I have a linear linked list where every node has 3 dynamically allocated char arrays and a next pointer(heads) to another linked list that also has 1 dynamic char array. In other words the data structure is a linked list of linked list. This is what I wrote:

nodea * tempa = heada;//create a new node to
nodesongs *temps=heada->heads;

while(heada)// while the list is not empty
{

        tempa= heada ->nexta;// traverse the list
        delete [] heada->dataa.name ;
        delete [] heada->dataa.story ;
        delete [] heada->dataa.description ;

        while(heada->heads)
        {
                temps = heada ->heads->nexts;
                delete[] heada->heads->datas.title;
                delete heada->heads;
                heada->heads = temps;
        }
      delete heada;
      heada = tempa;

}

I'd appreciate if you have a look at it and also would like to know if there is a common way people test their codes for memory leaks?

Upvotes: 1

Views: 356

Answers (4)

eerorika
eerorika

Reputation: 238411

How to confirm you are not having memory leaks?

There is no standard way for a C++ program to inspect its own state and find a memory leak.

There are however programming tools that can detect if a particular execution has leaked memory. These can tell you what was leaked, but that doesn't necessarily help you understand why it was leaked.

What you can do is analyse the program that you've written, and logically deduce whether any manually allocated memory would be leaked. This is extremely difficult to do in general (which is why compilers cannot do it for you), but it can become manageable if you follow best practices:

  • Never manage memory manually (99,99% chance that you don't need to)
    1. Never call new, nor malloc
    2. Always wrap owned pointers in smart pointers immediately after receiving them
    3. Always read the documentation of the libraries that you use. If a function gives you a bare pointer, double check whether you're responsible for disposing it; if you are, see 2.
      • This is typical when dealing with libraries that have a C API. Sometimes also with old or badly designed C++ API's.
  • If you do manage memory manually (but don't, because you don't need to)
    • Only ever do so in RAII fashion
      1. The owning pointer should be a private member of a class. This encapsulation reduces the scope that you have to analyse from the entire program to the member functions of this class.
        • Don't ever return references or pointers to this member, only copies (maybe not even that). Returning a reference would break the encapsulation (only non-const references, but there is no point in returning a pointer by const reference).
      2. Class invariant: The pointer must always point to null or a valid dynamically allocated object; No other instance of the class may point to this object.
        • If the member is allowed to not point to a valid dynamically allocated object (or null), then destructor of an object in such state would have undefined behaviour.
        • If several objects were allowed to own the same pointer, then destroying one would cause the other object to violate the invariant about pointing to valid object.
        • The implicit copy/move constructor and assignment operator perform a shallow copy which would cause violation of these invariants. Therefore we must follow the rule of 3 (or 5)
      3. The destructor of the class has to delete the pointer
      4. Any single time that member is assigned, either delete to old value, or "transfer" its ownership to another object (unless the pointer has an unspecified value, which it can only be within a constructor due to 5.). These assignments are where you're most likely to accidentally leak memory.
      5. Only have at most 1 owned bare pointer per class. Use nested classes if necessary. This suggestion is to make it possible / easier to guarantee exception safety. Lack of exception safety is the more subtle way to leak memory.

About your code, let us assume that you have to manage memory manually, to learn how to do it, so my suggestions 1 and 2 are not an option:

delete [] heada->dataa.name ;
delete [] heada->dataa.story ;

Bad 1: Don't delete pointers owned by other objects. This violates my suggestion 6. Delete in the destructor of that object instead.

Bad 2: During the lifetime of the container object (*heada), don't let the pointers point to an object that was deleted This is a consequence of Bad 1. and violates my suggestion 5.

Bad 3: Don't have multiple bare owning pointers in a single object. This violates my suggestion 8.

Upvotes: 4

There is no definitive way (see e.g. Rice's theorem), however:

In some cases, using some (or thinking in terms of) garbage collector can be helpful. Sometimes coding your own marking GC is easy and worthwhile. See also Boehm's GC. BTW, sometimes C++ is not the best language for the job.

Upvotes: 2

Caleth
Caleth

Reputation: 63059

Comment expanded to an answer:

You should strive to write code where memory leaks are not possible, and this is reasonably achievable with some discipline. If you are not allowed to use things in namespace std, then write facsimilies of your own.

E.g. the only place that uses new:

template<typename T>
struct pointer
{
  template<typename ... TArgs>
  pointer(TArgs&&... targs) : p(new T(targs...)) {}
  pointer(const pointer & other) = delete;
  pointer& operator=(const pointer & other) = delete;
  pointer(pointer && other) : p(other.p) { other.p = nullptr; }
  pointer& operator=(pointer && other) { std::swap(this->p, other.p); }
  ~pointer { delete p; }
  T& operator*() { return *p; }
  T* operator->() { return *p; }
private:
  T * p = nullptr;
}

Upvotes: 2

UKMonkey
UKMonkey

Reputation: 6993

While the comments are right about 'use smart pointers' they don't help you find what you're looking for.

Since it's platform dependant, the tool you're looking for is a tool called a memory profiler.

There's a few available, some paid, some not, and most platform specific. One that I can recommend if you're on Linux though is valgrind.

Upvotes: 1

Related Questions