Why can not I free memory?

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 logic of the language when calling the delete function, it should release 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 why?

    
asked by anonymous 01.04.2014 / 22:16

4 answers

4

It turns out that when you use the delete operator the 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 to the pointer to avoid confusion.

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

The computer does this to gain performance, if you know 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 only marked as empty but the data is still there, so sometimes it is possible to rescue deleted files.

    
01.04.2014 / 23:11
6

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

By analyzing your code we have A to get the pointer to a newly allocated memory, a list. Then you make B point to the same location as A . Then it deletes the list in memory pointed to by A , which is the same as B . Now both pointers point to an invalid region of memory. When attempting to execute delete B you invoke undefined behavior . Anything can happen from here, most likely nasal demons .

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

=================================================================
==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
    
01.04.2014 / 22:57
3
To begin with, the fact of running delete[] A; has no effect on pointer A, specifically, it only affects the memory that the system allocated and that has at address A the address that was allocated, much less the pointer B. Both are distinct entities.
It is up to you, as a good programming practice, to assign NULL to the pointers that were released. As for the pointer B, what fault does it have to be simply a copy to the memory area that was flushed using another pointer? None. In this case it is also your responsibility to control its use, since being a copy may be pointing to an area that is no longer part of the process.

    
01.04.2014 / 22:58
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 one is for arrays .

    
02.04.2014 / 01:43