12

I'm new to the language and I have a basic doubt about memory leaks. Is it possible to have a leak if I don't use the new keyword? (i.e having my variables in the stack and using data containers like std::vector)

Should I worry about this issue?

If that is the case, can someone give me an example of a situation that creates a leak without dynamically allocating memory?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
MonkeyCoder
  • 131
  • 5

3 Answers3

7

i.e having my variables in the stack and using data containers like std::vector

No, with std::vector or other standard containers you shouldn't have to worry.

can someone give me an example of a situation that creates a leak without dynamically allocating memory?

One popular mistake are circularly dependent smart pointers of the form:

class Child;
class Parent {
     std::vector<std::shared_ptr<Child>> childs;
};

class Child {
     std::shared_ptr<Parent> parent;
};

Since the reference counters of the shared pointers will never drop to zero those instances never would be deleted and cause a memory leak.

More info about what causes that and how to avoid it can be found here

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
4

I think it is not possible to leak memory if you do not reserve memory dynamically. Probably, global variables are not going to be freed, but I would not call that a memory leak.

However, there are more ways to dynamically reserve memory than using the keyword new.

For example, malloc allocates a memory block. Also calloc reserves memory and zeroes it.

Your operating can also give you methods to manage the memory. For example strdup for Linux.

You can also be using smart pointers and calling std::make_unique or std::make_shared. Both methods dynamically allocate memory.

For std::unique_ptr you can leak if you call release() and forget to delete the pointer.

 std::make_unique<int>(3).release(); // Memory leak

For std::shared_ptr you can leak if you create a circular reference. You can find more information here.

Also, when you use static variables, the destructor is not called when the variable goes out of scope but at the end of the execution. This is not exactly a memory leak because the destructor is finally called but you may have some memory allocated and not used.

For example, consider the following code:

#include <iostream>
#include <string>
#include <vector>

void f() 
{
    static std::vector<int> v;
    v.insert(v.begin(), 100*1024*1024, 0);
    v.clear();
}

int main()
{
    f();
    return 0;
}

std::vector::clear() is not required to free the memory allocated by the vector. So, after calling f(), you will have 400 MB of memory allocated but only accesible inside f(). Not exactly a memory leak, but it is a resource allocated that it is not automatically freed until the end.

J. Calleja
  • 4,855
  • 2
  • 33
  • 54
  • Very nice. Thank you for the examples. Specially the last one i think i might have that mistake! – MonkeyCoder Jan 23 '19 at 23:01
  • 3
    There is nothing wrong with having a static vector. This is not a particularly good answer. –  Jan 23 '19 at 23:19
  • 1
    @Neil Having a static vector is OK. But, if you only push elements and never pop them it will only grow and it is never deleted. – J. Calleja Jan 23 '19 at 23:22
  • @J.Calleja Destructor will be called on normal program exit. –  Jan 23 '19 at 23:23
  • You are right. Destructor is called at the end. This was a simplification of an actual example were we created an static vector an make It grow until the memory exhausted. I will update the answer. – J. Calleja Jan 23 '19 at 23:32
  • " memory usage will grow with each call to the function" - what does that have to do with memory leaks? Tere are many ways calling a function can cause memory usage to grow, but that does not imply a leak. –  Jan 23 '19 at 23:53
  • @NeilButterworth even in GC languages, this is considered a memory leak. – user253751 Jan 24 '19 at 00:23
  • @Neil I understand a leak as a resource you have lost control of. After calling f() you have memory reserved that you cannot free. Even if the function only uses vector internally. Obviously, there are valid uses of static variables, but you must remember to clear (and shrink) them when you no longer need them. – J. Calleja Jan 24 '19 at 00:42
  • Neil is correct. This does not leak. The destructor will be called and memory correctly released before program termination. There is no resource leakage and all contained objects would also be correctly be destroyed. – Martin York Jan 25 '19 at 09:53
  • @MartinYork It is stated in the answer that the memory is freed at the end. I wanted to note that, even using vectors, the memory may not be released when the variable goes out of scope. I understand that, when a resource is allocated but it is nor used nor accesible, it is simmilar to a memory leak. I have tried to clarify the issue in the answer. – J. Calleja Jan 26 '19 at 11:51
  • `even using vectors, the memory may not be released when the variable goes out of scope.` You are picking scope to fit your argument but its not relavant. The Standard talks about lifetime. The lifetime of a static variable is well defined and guarantees the objects destruction. – Martin York Jan 27 '19 at 09:11
  • `I understand that, when a resource is allocated but it is nor used nor accesible, it is simmilar to a memory leak.` Badly articulated, but still wrong. A leak is when it can not be accessed. – Martin York Jan 27 '19 at 09:12
  • @MartinYork I could not find the definition for memory leak in the C++ Standard. Wikipedia defines memory leak as "(...) a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released.". My example shows a case where the memory is not released after it is no longer needed. I agree the destructor will be called before the end of the execution. I agree it is not a complete memory leak. However, I think it is a good example of a problem OP may experience even if only std::vectors are being used. – J. Calleja Jan 28 '19 at 19:55
  • @J.Calleja Even by your definition it is not a leak. Its also a terrible example (as noted by both Neil and I). The memory is released so it is not leaked. You never loose the reference to it. So it is not leaked. It is ued every time `f()` is called so you can continue to use it for the life of the application. This is a leak in nobodies mind apart from yours. – Martin York Jan 28 '19 at 20:11
  • @MartinYork I may not call f() again and the memory will remain reserved until the end of the application. Note that I would not call it a leak if the data or the memory is going to be reused. However, if I find a method that reserves memory, it does not free it and it is not going to use it again, I would call it a leak (and it complies with the definition from Wikipedia). For me, it is not so important that the memory is released at the end (after all, every resource is released when the process exits). It is important to control the memory usage while the application is running. – J. Calleja Jan 28 '19 at 21:11
  • @J.Calleja But you may call `f()` again. And the memory will be there for you. So it is not a leak. `every resource is released when the process exits` Not 100% true. There are lots of resources that are not automatically released when the processes exits. These resources will eventually time out and be released but that can be well after the processes exits. You are twisting the meaning if you think it complies with the Wikipedia definition. – Martin York Jan 28 '19 at 22:03
4

In addition to the other answers, an easy source for memory leaks are external libraries. A lot of them, especially C or C-like libraries, have functions like create_* and destroy_* for their data types. Even though you never explicitly call new, it is still just as easy to have a memory leak.

sudgy
  • 491
  • 1
  • 3
  • 15
  • 1
    My personal suggestion for avoiding this problem is to wrap the type in a simple RAII class, or use a `std::unique_ptr` with a custom deleter. – sudgy Jan 24 '19 at 06:03