Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does C++ do at the memory address of a variable to "deallocate" it?

For example .
When a function, that has a local integer variable x, ends, what does C++ do to the value stored at memory location corresponding to x?
Does it insert a random value?

like image 816
Damian Siniakowicz Avatar asked Sep 02 '18 13:09

Damian Siniakowicz


4 Answers

What's probably happening - is nothing. Deleting something takes resources, so instead it just adjusts the pointer of the stack that is pointing to this memory. This will lead to overwriting it next time this memory is used.

You can see a similar thing while using a variable without initializing it.

int i;

i will have "garbage" data in it, this "garbage" is from a time where this specific location in memory was in use. Could be an old photo, a text file or w/e.

like image 115
sagi Avatar answered Nov 10 '22 04:11

sagi


This very much depends on the implementation.

In most cases nothing is done. You deallocate (which changes the stack pointer). You don't modify the memory in this case.

In some very obscure cases you may find different things done. In one example, the RTOS RTEMS can be set up to write to the memory in dealocation. It might write something specific like 0xCDCDCDCD or 0xDEADBEEF. This can be helpful when debugging memory issues in these RTOS systems because it is easy to identify when you are using bad memory. But this is very rare.

like image 41
Fantastic Mr Fox Avatar answered Nov 10 '22 03:11

Fantastic Mr Fox


In theory this is not specified, but in practice no allocation is taking place for individual basic-type objects like int, double, T*, etc. In some cases, the stack pointer is not modified and the compiler simply reuses the space for other variables:

for (int i=0 ; i < 10 ; i++)
   foo(i);
for (int j=0 ; j < 10 ; j++)
   foo(j);

Most likely, the compiler will reuse the space of i for allocating j. This is easily verified on godbolt.org with gcc:

.L2:
        mov     edi, ebx
        add     ebx, 1
        call    foo(int)
        cmp     ebx, 10
        jne     .L2
        xor     ebx, ebx
.L3:
        mov     edi, ebx
        add     ebx, 1
        call    foo(int)
        cmp     ebx, 10
        jne     .L3

Not only the loops are identical, they don't even use the stack. Instead of the stack, both i and j variables are allocated on the `ebx. In this example, allocation and deallocation are completely transparent and are a simple use or no-use of registers.


A more complicate example will do the same on the stack:
int foo(int);
void bar(int*);
void bar()
{
    {
        int a[10];
        for (int i=0 ; i < 10 ; i++)
            a[i] = foo(i);
        bar(a);
    }
    {
        int b[10];
        for (int j=0 ; j < 10 ; j++)
            b[j] = foo(j);
        bar(b);
    }
}

Also, consulting second godbolt.org example produces:

        xor     ebx, ebx ; <--- this is simply part of the next block
        sub     rsp, 48;   <--- allocating the stack space
.L2:
        mov     edi, ebx
        call    foo(int)
        mov     DWORD PTR [rsp+rbx*4], eax
        add     rbx, 1
        cmp     rbx, 10
        jne     .L2
        mov     rdi, rsp
        xor     ebx, ebx ; <--- this is simply part of the next block
        call    bar(int*)
.L3:
        mov     edi, ebx
        call    foo(int)
        mov     DWORD PTR [rsp+rbx*4], eax
        add     rbx, 1
        cmp     rbx, 10
        jne     .L3
        mov     rdi, rsp
        call    bar(int*)
        add     rsp, 48  ; <-- deallocating the stack space

Here also, the code is identical for the two cases. There is no deallocation or allocation of the variables on the stack. The line:

        a[i] = foo(i);

is translated into

        mov     DWORD PTR [rsp+rbx*4], eax

which simply writes data relative to the stack pointer (rsp). It basically finds the contents of a according to its position relative to the stack pointer. The stack pointer is not updated between the two blocks of code, it is only passed to bar() by copying the stack pointer to rdi:

        mov     rdi, rsp
        call    bar(int*)


As I have shown, usually during the running of a block no allocation and deallocaiton take place. Typically, at the beginning and the end of a function, the stack-pointer is updated to reflect the variables.

Unlike simple integer values, types with destructors are more complicated, but I will not go deeper on that because it was not asked in the question.

like image 38
Michael Veksler Avatar answered Nov 10 '22 04:11

Michael Veksler


If you are creating an object and allocating a pointer to it

Animal* animal =new Animal() ;

It will allocate a memory region in the memory.It is like you are building a house and giving address to someone.

delete animal;

Will go to that memory region and destroy it.Like you trace the house with the address and destroying it. Then the value it holds will be garbage. As a good practice you have to make the address of the house nullptr.

animal = nullptr;
like image 28
Kethiri Sundar Avatar answered Nov 10 '22 03:11

Kethiri Sundar