Matt Bart
Matt Bart

Reputation: 949

Memory Leak with Pointers C++

I'm new to C++ and I found out that I have been spoiled by Java and newer programing languages like Swift. So I understand that sometimes you have to delete objects manually in C++ such as pointers. You can use the delete keyword or you can use the smart pointers. But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.

I'm writing code that acts as a integer linked list. So I have a pointer pointing to the head and the tail of the list. When ever someone 'polls' something it should delete it from the list and then reset the head (or tail) accordingly. So I have some code that works fine for what I need it to do:

int IntegerLinkedList::pollFirst(){
    if (tail == nullptr && head == nullptr) {
        return 0;
    } else if (head == tail) {
        int ret = head->getData();
        head = nullptr;
        tail = nullptr;
        //delete head;
        //delete tail;
        return ret;
    } else {
        IntegerNode* newHead = head->getNext();
        head->setNext(nullptr);
        newHead->setPrevious(nullptr);
        int ret = head->getData();
        //delete head;
        head = newHead;
        return ret;
    }
}

But I never really delete the object that it was pointing at, I just remove all the pointers to it. Does that delete the object like it would in Java? Or do I have to manually delete it and how would I do that? Am I memory leaking??? Thanks so much

Also the code that updates the head is

 void IntegerLinkedList::addFirst(int x){
    IntegerNode* n = new IntegerNode(x);
    if (head == nullptr && tail == nullptr) {
        head = n;
        tail = n;
    } else {
        head->setPrevious(n);
        n->setNext(head);
        head = n;
    }
}

And the head was defined in the header as

 IntegerNode* head;

Upvotes: 0

Views: 980

Answers (6)

Will R.
Will R.

Reputation: 453

If you use the new keyword, then you always need to use delete. Memory allocated using new is not managed.

Currently your program is leaking memory in the pollFirst method, because you do not free the memory that head and tail point to before re-assigning them. You can do this by calling delete head and delete tail before re-assignment.

You should look into using one of the smart pointer types, such as unique_ptr, if you want automatic management of the memory your pointers point to.

Upvotes: 1

Guillaume Racicot
Guillaume Racicot

Reputation: 41840

Am I memory leaking???

Yes, if you new something, you must delete somewhere. Assigning pointer to nullptr won't ever affect the allocated data.

But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.

The delete keyword will delete the content at the address you send to it. It won't delete named variable, as variable on the stack are destructed at the end of the scope. Deleteting manually something with automatic storage led to undefined behaviour.

I see you are confused about std::unique_ptr No, they are not deleting themselves. Like any other variable, thier destructor are called and the variable is destructed. The thing about std::unique_ptr is that in their destructor, they delete the data they point to, with you having to delete it yourself. You should read about the RAII idom.

There's a thing about your code, these lines in particular:

head = nullptr;
tail = nullptr;
delete head;
delete tail;

This won't do a thing. You are deleting no data, as head and tail point to nothing. Since the delete keyword deletes the data pointer are pointing to, it won't delete anything.

However, take this example with std::unique_ptr:

{
    std::unique_ptr<int> myPtr;

    myPtr = std::make_unique<int>(); // or you can use `new int;`

    myPtr = nullptr; // The old int you allocated with `std::make_unique` is deleted.

    myPtr = std::make_unique<int>(); // assign a newly allocated int
}
// Here, myPtr will free his data as it leaves the scope.

Upvotes: 1

Apoorva sahay
Apoorva sahay

Reputation: 1930

There are few things you should know about C++.

  • Destructor (DTOR) : Destructor is something which you define for your class. If you don't define a destructor of your own compiler does it for you.
  • When you call delete for a pointer the DTOR of that class is called which does the necessary cleanup. In order to test it, please put a breakpoint to the DTOR and run the code. Once the control hits DTOR, check the call stack, you will find out that last frame below the DTOR in call stack is the line where you call delete.
  • As far as the smart pointers are concerned, it does something similar to the garabage collector. Smart pointers have something called reference count. The moment reference count of a smart pointer goes to 0, the DTOR is called.

NOTE: It is advised to write your own DTOR if you have a data member in the class which is pointer.

Upvotes: 0

Robert Pr&#233;vost
Robert Pr&#233;vost

Reputation: 1717

It depends on what the type is for head and tail. In C++, there are operators (e.g., operator=), and there are destructors. This can lead to certain interesting consequences. Take this example:

#include <memory>

int main() {
    // allocate memory
    int* ptr = new int;
    // store in smart pointer
    std::unique_ptr<int> smart_ptr(ptr);
    // create another wrapped pointer
    std::unique_ptr<int> smart_ptr2(new int);
    // throw away location of allocated memory
    ptr = nullptr;
    // free memory by assigning to smart pointer
    smart_ptr = nullptr;
    // we can call delete safely here because ptr is null
    delete ptr;
    // data pointed to by smart_ptr2 will
    // be deleted at end of scope
    return 0;
}

Additionally, there are two operators for allocating memory, operator new and operator new[], which must be free'd using delete and delete[] respectively.

A more detailed explanation of these concepts may be beyond the scope of this site.

Upvotes: 1

Assimilater
Assimilater

Reputation: 964

Java has a garbage collector that essentially does what smart pointers do. That is, when the last reference to an object falls out of scope clean up the memory.

The delete keyword frees up the memory at a location the pointer points to. It doesn't actually do anything to the pointer variable itself (which is just an address).

The way to correct your code would be:

else if (head == tail) { // suppose head = 0xAD4C0080
    int ret = head->getData();
    delete tail; // cleans memory at 0xAD4C0080, head and tail are still 0xAD4C0080
    head = nullptr; // now head = 0
    tail = nullptr; // now tail = 0
    return ret;
} else {
    IntegerNode* newHead = head->getNext();
    head->setNext(nullptr);
    newHead->setPrevious(nullptr);
    int ret = head->getData(); // obtain data while head still exists
    delete head; // get rid of head
    head = newHead; // remove stray reference to deleted memory
    return ret;
}

If you attempted to use the value 0xAD4C0080 after calling delete in these examples you would get a segmentation fault.

As for smart pointers (quoting from your comment):

yes the smart pointers, but do they delete what it is pointing at or just themselves

Smart pointers delete what they are pointing to when they themselves get deconstructed (usually by falling out of scope). i.e.

void func() {
   std::unique_ptr<int> pInt(new int);
} // pInt falls out of scope, std::unique_ptr<int>::~std::unique_ptr<int>() called

Upvotes: 1

Sam Varshavchik
Sam Varshavchik

Reputation: 118435

I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.

It deletes what the pointer is pointing to. The pointer must be pointing to an object that was allocated with dynamic scope (the new keyword).

I just remove all the pointers to it. Does that delete the object like it would in Java?

Of course not.

Or do I have to manually delete it and how would I do that? Am I memory leaking???

You have to manually delete it, using the delete keyword, and, yes, you are leaking memory unless you do that.

It is often said that it's easier to learn C++ from scratch, than to try to learn C++ if you already know Java. C++ objects work fundamentally differently than they work in Java.

And not only differently, but in ways that have no equivalent in Java, at all. There is no Java equivalent, for example, of an object instantiated in automatic scope, in C++.

The full explanation of various scopes of C++ class instances cannot be fully given in a brief answer on stackoverflow.com. You need to get a good book on C++, and start reading it.

And forget everything you know about classes from Java. C++ classes don't work that way. The longer you keep trying to draw analogies with Java, the longer it will take you to learn how to use C++ classes correctly.

Yes, some of the pain can be helped by using smart pointers, which will take care of some of the pain points. But understanding smart pointers in of themselves also requires complete understanding of C++'s class model. Smart pointers do not solve everything, and it is important to understand how C++ classes work, in order to understand what problems smart pointers do solve, and what problems they do not solve.

Upvotes: 1

Related Questions