Why Does the Use of 'New' Cause Memory Leaks

Why does the use of 'new' cause memory leaks?

What is happening

When you write T t; you're creating an object of type T with automatic storage duration. It will get cleaned up automatically when it goes out of scope.

When you write new T() you're creating an object of type T with dynamic storage duration. It won't get cleaned up automatically.

new without cleanup

You need to pass a pointer to it to delete in order to clean it up:

newing with delete

However, your second example is worse: you're dereferencing the pointer, and making a copy of the object. This way you lose the pointer to the object created with new, so you can never delete it even if you wanted!

newing with deref

What you should do

You should prefer automatic storage duration. Need a new object, just write:

A a; // a new object of type A
B b; // a new object of type B

If you do need dynamic storage duration, store the pointer to the allocated object in an automatic storage duration object that deletes it automatically.

template <typename T>
class automatic_pointer {
public:
automatic_pointer(T* pointer) : pointer(pointer) {}

// destructor: gets called upon cleanup
// in this case, we want to use delete
~automatic_pointer() { delete pointer; }

// emulate pointers!
// with this we can write *p
T& operator*() const { return *pointer; }
// and with this we can write p->f()
T* operator->() const { return pointer; }

private:
T* pointer;

// for this example, I'll just forbid copies
// a smarter class could deal with this some other way
automatic_pointer(automatic_pointer const&);
automatic_pointer& operator=(automatic_pointer const&);
};

automatic_pointer<A> a(new A()); // acts like a pointer, but deletes automatically
automatic_pointer<B> b(new B()); // acts like a pointer, but deletes automatically

newing with automatic_pointer

This is a common idiom that goes by the not-very-descriptive name RAII (Resource Acquisition Is Initialization). When you acquire a resource that needs cleanup, you stick it in an object of automatic storage duration so you don't need to worry about cleaning it up. This applies to any resource, be it memory, open files, network connections, or whatever you fancy.

This automatic_pointer thing already exists in various forms, I've just provided it to give an example. A very similar class exists in the standard library called std::unique_ptr.

There's also an old one (pre-C++11) named auto_ptr but it's now deprecated because it has a strange copying behaviour.

And then there are some even smarter examples, like std::shared_ptr, that allows multiple pointers to the same object and only cleans it up when the last pointer is destroyed.

Does using the new statement on an already created object cause memory leaks?

The premise of your question is flawed.

You never call new on an already-created object. You call new, and you always (by specification) get a new object (or something like an exception or error occurs).

What you are asking about here is assigning them to a variable or a field. In and of itself, it makes no difference whether it is a variable or a field from a memory leak perspective. It also makes no difference whether this field or variable is also initialized: you are just replacing a reference to one object with a reference to another.

The only thing which would make a difference is if you also add the object to a List (or some other collection, array etc), or add the object which contains the field to a List etc: then, it would not be possible to garbage collect, since the object is still reachable. Then you would have a memory leak.

Why is this function causing memory leak?

Memory is leaked because there is no destructor to free the allocated Nodes. The asker notes that they removed the destructor because the program crashed when they had one. This is the error that should have been addressed because having a destructor is the correct thing to do.

Solution

Put the destructor back and solve why the destructor caused the program to crash.

Solution for the Solution

List violates the Rule of Three. This means when a List is copied and you have two objects both pointing to the same head Node. This Node can only be deleted once and both objects will try to delete it in the List destructor. Sooner or later the program dies a painful death.

Normally you could replace the passes by value with passes by reference, and then disallow copying by deleteing the special member functions. Eg. add

List(const List & src) = delete;
List& operator=(List src) = delete;

to List and wait for the compiler to start screaming about List being copied when the copy special functions are deleted. Replace all of the passes by value with passes by reference.

Unfortunately

List<bibliography> readBibliographyFile(char * filename)

returns by value. Return by reference of a local variable is doomed. The local variable goes out of scope and is destroyed, leaving you with a reference to an invalid object. This means you have to do this the hard way:

Implement all three special member functions:

// destructor
~List()
{
while (head)
{
Node<T> * temp = head->next;
delete head;
head = temp;
}
}

// copy constructor
List(const List & src): head(NULL), length(src.length)
{
Node<T> ** destpp = &head; // point at the head.
// using a pointer to a pointer because it hides
// the single difference between head and a Node's
// next member: their name. This means we don't need
// any special cases for handling the head. It's just
// another pointer to a Node.
Node<T> * srcnodep = src.head;
while (srcnodep) // while there is a next node in the source list
{
*destpp = new Node<T>{srcnodep->data, NULL}; // copy the node and store it at
// destination
destpp = &((*destpp)->next); // advance destination to new node
srcnodep = srcnodep->next; // advance to next node in source list
}
}

List& operator=(List src) // pass list by value. It will be copied
{
length = src.length; // Technically we should swap this, but the copy
// is gonna DIE real soon.
// swap the node lists. use std::swap if you can.
Node<T> * temp = head;
head = src.head;
src.head = temp;

// now this list has the copy's Node list and the copy can go out of scope
// and destroy the list that was in this List.

return *this;
}

Notes

operator= is taking advantage of the Copy and Swap Idiom. It's often not the fastest solution, but it's easy to write and next to impossible to get wrong. I start with Copy and Swap and only migrate to something faster only when profiling the code's performance shows I have to, and that almost never happens.

The pointer-to-pointer trick used in the copy constructor also comes in really handy when inserting and removing list items.

Know and understand the Rule of Three and its friends. You cannot write complex and efficient C++ programs without it. It is possible that this assignment was given, at least in part, to force you to learn it.

Does 'new' cause a memory leak in Java?

In short, no. Java has a built-in (and mandatory) garbage collector. C++ does not.

Once an Object is no longer reachable (in Java), it is eligible for garbage collection (and the collector may free the memory).

Can I have memory leaks if I'm not using new keyword?

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.

Memory leak with new operator and &? C++

It will cause a memory leak. What your doing there is allocating a block of memory, dereferencing the pointer and assigning it to the variable var. Dynamic memory allocation does not deallocate itself when gone out of the scope, instead the variable var will be destroyed, not the pointer that you allocated.

To delete it, what you need to do is something like this,

int& var = *new int(5);
delete &var;

Would calling the default parameter with `new` cause memory leak?

Yes, that introduces a memory leak. You might instead consider using a tuple return value:

std::tuple<cv::Point, cv::Mat> detect(const cv::Mat &img);

or making mask a pointer:

cv::Point detect(const cv::Mat &img, cv::Mat *mask = nullptr);

You could also try to keep the same signature with a cast. This is ugly but it might work:

cv::Point detect(const cv::Mat &img, cv::Mat &mask = const_cast<cv::Mat&>(static_cast<cv::Mat const&>(cv::Mat())));


Related Topics



Leave a reply



Submit