Why can’t I release memory?

Asked

Viewed 1,095 times

6

I have the following code:

#include "iostream"

int main(){

    int* A = new int[4];
    int* B = A;
    delete[] A;
    delete B;

    if(B == NULL)
        std::cout << "B = NULL" << std::endl;
    else
        std::cout << B << std::endl;

    if(A == NULL)
        std::cout << "A = NULL" << std::endl;
    else
        std::cout << A << std::endl;

    return 0;

}

By the logic of the language when calling the delete function, it should free the space in memory, so it should enter the loop that makes the conference for me if value is NULL, but this does not occur.

Can anyone explain to me why that?

  • 5

    Choose to use #include <iostream> with <iostream> instead of "iostream". When you use quotes, the compiler will search iostream in the directory of your program and, as you won’t find, (only then) will search in the system directory.

  • To complement Lucas Nunes' comment, use double quotes to include only your local files. Regarding your question, when using delete memory is released but content is not changed immediately. This can cause undefined behavior. In this case, it is valid to delete the pointer delete B; and then define as null B = NULL;. In any case, whenever possible use smart pointers. In this guide you can find some good practices in C++.

4 answers

6

First of all, delete releases the memory pointed by the pointer, but does not touch the pointer itself. It will continue to point to where the data was before.

Analyzing your code we have to A will receive the pointer to a newly allocated memory, a list. Next you do B point to the same location as A. Then delete the list in the memory pointed by A, which is the same pointed out by B. Now both pointers point to an invalid memory region. When trying to run delete B you invoke Undefined behavior. Whatever can happen from here, most likely nasal demons.

This problem is commonly known as double free and various memory analysis tools can detect this error in your program, such as Sanitizer address. Compiling your code with g++ main.cpp -o main -fsanitize=address and executing the result, I have the second exit:

=================================================================
==11122== ERROR: AddressSanitizer: attempting double-free on 0x60040000dff0:
    #0 0x7ff3c90e39da (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0x119da)
    #1 0x400b89 (/home/guilherme/main+0x400b89)
    #2 0x7ff3c8a29ec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
0x60040000dff0 is located 0 bytes inside of 16-byte region [0x60040000dff0,0x60040000e000)
freed by thread T0 here:
    #0 0x7ff3c90e3a4a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0x11a4a)
    #1 0x400b7d (/home/guilherme/main+0x400b7d)
    #2 0x7ff3c8a29ec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
previously allocated by thread T0 here:
    #0 0x7ff3c90e388a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0x1188a)
    #1 0x400b5e (/home/guilherme/main+0x400b5e)
    #2 0x7ff3c8a29ec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
==11122== ABORTING

4


It turns out that when you use the operator delete memory is not actually deleted, it is only marked as "free" for use, the pointer is also not modified, it is your duty to assign NULL pointer to avoid confusion.

So when using the operator delete memory remains accessible, but as new allocations are being made it will happen that your previously deleted memory will be given to another variable and then your pointer will be pointing to a corrupted memory block.

The computer does this to gain performance, if you know that that memory is "free" there is no reason to waste time filling it with zeros. The same scheme is done in Hds, the spaces are just marked as empty but the data is still there, so sometimes it is possible to rescue deleted files.

  • Thank you, what happened is that I had not understood the concept of memory allocation and release.

  • 4

    Strictly speaking, memory is not always accessible. By joining several blocks marked as free, the library can decide to return the page to the system. So the process can no longer access the memory (access = Segmentation Failure).

  • That too William, well remembered.

3

For starters, the fact of executing delete[] A; does not have any effect on pointer A, specifically, only affects the memory that the system has allocated and that has in the Port A the address that was allocated and much less the pointer B. Both are distinct entities.
It is up to you, as good programming practice, to assign NULL to the pointers that have been released. Regarding pointer B, what fault does it have to be simply a copy to the memory area that was released using another pointer ? None.
In this case it is also your responsibility to control its use, since by being a copy you may be pointing to an area that is no longer part of the process.

  • 2

    If the compiler supports C++11 (and/or is set to), you can use nullptr instead of NULL. Just to add.

1

Hello, you can use the following functions.

// C++
template <class T> void SDEL(T*& val)
{
    delete val;
    val = NULL;
}

template <class T> void SDEL_ARRAY(T*& val)
{
    delete[] val;
    val = NULL;
}

// uso
// Ponteiro de arrays
int* my_int = new int[2];
my_int[0] = 100;
my_int[1] = 200;

std::cout << "my_int: " << my_int[0] << ", " << my_int[1] << std::endl;

SDEL_ARRAY(my_int);

The first is for common objects. The second is for arrays.

  • 4

    Checking whether the pointer is null is unnecessary. The operator delete already check that too.

  • @C.E.Gesser, I’ve updated your answer.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.