What means 'destroying' memory by delete operator in C++? - c++

I would like to know what happens to memory that is destroyed by "delete" operator in C++.
Is 'destroying' memory in such way means setting given pieces of memory to 0 or something else?

It is destroying (as in calling the relevant destructor for) the object instance passed to delete, and then "frees" the memory so that it can be used for other purposes.
The C++ standard states nothing about what the contents of the memory will be after delete, and it is certainly not guaranteed to be zero or any other value - nor is it guaranteed that it is NOT zero - it may be zerod, it may retain all the values it had before, or some parts of it may be altered and others remain the same.
The goal of C and C++ as languages is to "only do the minimum necessary", so a typical memory free will not overwrite the "old" memory.
You could of course use code in the destructor to set the memory to zero before it is freed.
Since you are not supposed to use memory after it has been deleted, it shouldn't really matter.

delete just releases the memory (previously allocated by new) and in case that some object has been stored within this memory, the destructor is also invoked.
delete doesn't change the value of the pointer and neither it modifies the memory that has been released, thus you'll notice that many people are used to assign NULL to this pointer after calling delete just to make sure they will not end up with dereferencing invalid (dangling) pointer, which produces undefined behavior.
Worth to have a look at: Is it good practice to NULL a pointer after deleting it?

No, it does not mean setting the memory to any particular value+. The memory simply gets back into the heap of values that can be reused. The runtime often use several bytes of the returned chunk to store "bookkeeping" information, but they do not set the entire chunk to a particular value. Once a memory chunk is reused, it is your program that sets its new values.
+ There are memory profiling tools that let you set released memory to some "junk" values to make sure that you get a crash faster.

Related

How is memory deallocated in c++

I understand pointer allocation of memory fully, but deallocation of memory only on a higher level. What I'm most curious about is how C++ keeps track of what memory has already been deallocated?
int* ptr = new int;
cout << ptr;
delete ptr;
cout << ptr;
// still pointing to the same place however it knows you can't access it or delete it again
*ptr // BAD
delete ptr // BAD
How does C++ know I deallocated that memory. If it just turns it to arbitrary garbage binary numbers, wouldn't I just be reading in that garbage number when I dereference the pointer?
Instead, of course, c++ knows that these are segfaults somehow.
C++ does not track memory for you. It doesn't know, it doesn't care. It is up to you: the programmer. (De)allocation is a request to the underlying OS. Or more precisely it is a call to libc++ (or possibly some other lib) which may or may not access the OS, that is an implementation detail. Either way the OS (or some other library) tracks what parts of memory are available to you.
When you try to access a memory that the OS did not assigned to you, then the OS will issue segfault (technically it is raised by the CPU, assuming it supports memory protection, it's a bit complicated). And this is a good situation. That way the OS tells you: hey, you have a bug in your code. Note that the OS doesn't care whether you use C++, C, Rust or anything else. From the OS' perspective everything is a machine code.
However what is worse is that even after delete the memory may still be owned by your process (remember those libs that track memory?). So accessing such pointer is an undefined behaviour, anything can happen, including correct execution of the code (that's why it is often hard to find such bugs).
If it just turns it to arbitrary garbage binary numbers, wouldn't I just be reading in that garbage number when I dereference the pointer?
Who says it turns into garbage? What really happens to the underlying memory (whether the OS reclaims it, or it is filled with zeros or some garbage, or maybe nothing) is none of your concern. Everything you need to know is that after delete it is no longer safe to use the pointer. Even (or especially) when it looks ok.
How does C++ know I deallocated that memory.
When you use a delete expression, "C++ knows" that you deallocated that memory.
If it just turns it to arbitrary garbage binary numbers
C++ doesn't "turn [deallocated memory] to arbitrary garbage binary numbers". C++ merely makes the memory available for other allocations. Changing the state of that memory may be a side effect of some other part of the program using that memory - which it is now free to do.
wouldn't I just be reading in that garbage number when I dereference the pointer?
When you indirect through the pointer, the behaviour of the program is undefined.
Instead, of course, c++ knows that these are segfaults somehow.
This is where your operating system helpfully stepped in. You did something that did not make sense, and the operating system killed the misbehaving process. This is one of the many things that may but might not happen when the behaviour of the program is undefined.
I take it that you wonder what delete actually does. Here it is:
First of all, it destructs the object. If the object has a destructor, it is called, and does whatever it is programmed to do.
delete then proceeds to deallocate the memory itself. This means that the deallocator function (::operator delete() in most cases in C++) typically takes the memory object, and adds it to its own, internal data structures. I.e. it makes sure that the next call to ::operator new() can find the deallocated memory slab. The next new might then reuse that memory slab for other purposes.
The entire management of memory happens by using data structures that you do not see, or need to know that they exist. How an implementation of ::operator new() and ::operator delete() organizes its internal data is strictly and fully up to the implementation. It doesn't concern you.
What concerns you is, that the language standard defines that any access to a memory object is undefined behavior after you have passed it to the delete operator. Undefined behavior does not mean that the memory needs to vanish magically, or that it becomes inaccessible, or that it is filled with garbage. Usually none of these happens immediately, because making the memory inaccessible or filling it with garbage would require explicit action from the CPU, so implementations don't generally touch what's written in the memory. You are just forbidden to make further accesses, because it's now up to system to use the memory for any other purpose it likes.
C++ still has a strong C inheritance when it comes to memory addressing. And C was invented to build an OS (first version of Unix) where it makes sense to use well known register addresses or to whatever low level operation. That means that when you address memory through a pointer, you as the programmer are supposed to know what lies there and the language just trusts you.
On common implementations, the language requests chunks of memory from the OS for new dynamic objects, and keeps track of used and unused memory block. The goal is to re-use free blocks for new dynamic objects instead of asking the OS for each and every allocation and de-allocation.
Still for common implementation, nothing changes in a freshly allocated or deallocated block, but the pointers maintaining a list of free blocks. AFAIK few return memory to the OS until the end of the process. But a free block could be later re-used, that is the reason why when a careless programmer tries to access a block of memory containing pointers that has been re-used, SEGFAULT is not far, because the program could try to use arbitrary memory addresses that could not be mapped for the process.
BTW, the only point required by the standard is that accessing an object past its end of life, specifically here using the pointer after the delete statement invokes Undefined Behaviour. Said differently anything can happen from an immediate crash to normal results, passing through later crash or abnormal result in unrelated places of the program...

why it is a disater to have a pointer or reference to an object has been returned back to the memory heap in c++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
So I know that heap is where the memory is stored. Unlike stack, if the user does not delete the heap, the heap keeps existing.
However, I have problem with "an object has been returned back to the memory heap" part. Does returned back means that the object has been freed? If not, why it is a disaster to have a pointer/reference to that object?
Firstly, heap and stack are not C++ concepts. They refer to particular types of memory, as managed on some systems.
Second, what is often described as "heap" is, in C++, referred to as "dynamically allocated memory".
When dynamically allocated memory is released by the program (e.g. using operator delete on something obtained using operator new, using free() on a pointer returned by C's malloc()) that memory no longer exists as far as your program is concerned, but the pointer value does not change. Using a pointer or reference to something that no longer exists gives, in the language of the C++ standard, undefined behaviour.
Practically, the memory might exist physically on your system, or even still be allocated by the host system to your program. However, once it has been released by your program, there is nothing preventing the memory being reused. Your program might use operator new to allocate more memory, so the memory that was previously released is now being used for something else - completey unrelated to the original usage - by your program. That is inherently dangerous - the results can be anything (which is, loosely, the implication of undefined behaviour in the C++ standard).
The operating system might also have recovered the logical or physical memory (after all, your program has indicated no more use for that memory) and allocated it to another program. That is dangerous for both your program and the other program that has been allocated memory. Which is why most modern operating systems prevent that e.g. by forcably terminating your program if the operating system detects an access to memory it no longer owns.
A real danger is that you might access a released object for a while, and everything seems to work as required. Only to crash later on. There can often be a significant time interval between some memory being released by your program, and being reused for something else.
Such flaws in programs tend to infuriate users of that program (users, for some obscure reason, tend to be less than appreciative when programs crash in unpredictable and unrepeatable ways in the middle of their work). Such flaws in your code also tend to be very difficult to track down, and therefore hard to correct.
I have problem with "an object has been returned back to the memory heap" part. Does returned back means that the object has been freed? If not, why it is a disaster to have a pointer/reference to that object?
It might help to break down the terminology and clarify a few things:
Firstly, the term Object in C++ refers to something residing in memory, but does not refer to the memory itself.
It's worth making a distinction between an object and the memory storing the object because the actions of allocating memory and initialising an object are distinct and separate.
The following line is doing two things:
new int(123);
It is allocating an area of memory on the heap to your program whose size in bytes is equal to sizeof(int). The effect of the allocation of memory is not to create an object, nor is it even to change anything about the content of that memory; it is simply to ringfence that memory for your program to use.
Any "junk" or garbage values which might have been pre-existing in that memory will not be changed.
After the memory is allocated, that chunk of memory is initialised with an int object containing 123. Objects may only be initialised within an area of memory which is already allocated to your program.
Given that the new operator is doing two different things, it follows that the delete operator may also perform two different actions:
delete will destroy the object; this is usually limited to releasing resources owned by the object. Destroying an object typically does not bother to change or reset any memory which is about to be deallocated because that's usually a waste of CPU cycles.
After an object is destroyed, you might find the remains or partial remains of that object stuck around in memory for a while, but as far as your program is concerned, the object itself is dead/gone and the memory contents are junk.
delete will de-allocate the memory. The process of de-allocation is not to change the content of that memory, it is simply to release that memory for use by something else. Trying to access that area of memory after it has been deallocated is undefined behaviour.
Remember that a pointer cannot ever point-to an object because an object is "The thing in memory" rather than the memory itself; raw pointers in C++ are fairly simple/dumb - they don't track anything about the state of the objects in their pointed-to memory. If an object is moved or copied or destroyed, the pointer will know nothing about it.
A pointer is an address for a location in memory.
It helps to think of pointer-values (addresses) and pointer-variables which contain those values/addresses. Sadly the term pointer has historically had a bit of a double-meaning, to refer both to the pointer-value and the pointer-address, which can seem confusing.
Typically the memory location pointed-by a pointer-variable should contain a valid object within an allocated area of memory, but it also might not.
C++ does not protect you against dangling pointers, where a dangling pointer is a pointer-variable containing an address of an area of memory which has not been allocated to your program.
Neither does C++ protect you against pointers-to un-initialised memory (e.g. if you have allocated memory using malloc but not initialised its contents).
Lastly, C++ does not protect you against memory leaks; you as the programmer are responsible for keeping track of all your allocated memory.
These last 3 points are among some of the many reasons why new/delete tend not to be used very often in modern C++, and why & references, std::vector, std::shared_ptr and other alternatives are preferred; they take care of many nuances and gotchas surrounding new/delete.

What exactly happens when delete my_object; is executed? Is all other memory shifted to the left by sizeof(MyClass)?

For the sake of this question I will picture memory as a simple array of bytes, and I will be talking about heap memory because it is possible to dynamically allocate it.
Lets say that I am instantiating some class, and creating an object on the heap where some memory has already been allocated. Then, after creating the object, I allocate some more memory (maybe by instantiating another class). This implies the use of new and delete keywords, of course.
The memory now looks like this:
... byte byte my_object ... my_object byte byte ...
What exactly happens when delete my_object; is executed? Is all other memory shifted to the left by sizeof(MyClass)? If so, by who? The OS? Then what happens when there is no OS to provide virtual memory?
No, nothing gets shifted. Instead, memory gets fragmented, meaning that you now have a unused hole in the middle of used memory. A subsequent allocation might be able to re-use part or all of that memory (provided the requested number of bytes is small enough to fit in the hole).
Some languages/environments support compacting garbage collectors. Such collectors are permitted to move objects around and can therefore eliminate holes if they choose to. Such approaches are complicated to implement since the collector needs to know the location of every single pointer within the program. Collectors of this type are therefore more suitable for higher-level languages.
If the memory were shifted, that'd be a pretty bad OS IMO. Typically, the OS is notified that that memory is available for re-use. It's not even required to be cleared (and most of the time isn't). When no more memory can be allocated, you'd typically get an exception (if you're using new) or a NULL pointer back (if you're using malloc).
If fragmentation is a concern (it sometimes is), you'll have to write your own memory pool you can use (existing) memory pools which can deal with that, but even so, most of the responsibility still falls on the programmer.
Memory is not shifted to the left. Imagine what would happen if it was. All those pointers "on the right" would become invalid.
On a typical implementation (without a moving garbage collector for instance) nothing will be moved.
Bames53 says that Herb Sutter says that the standard says that automatic movement of allocated objects is illegal. Thanks Bames53.

What does the use of new require you to also call delete?

I am here stuck with a question in my C++ book with the following:
"What does the use of new require you to also call delete?"
Maybe you have an answer for that?
Because that is the way C++ is designed & that is the intended behavior.
The intention was to provide a memory allocation which you demand and own till you reliquish it explicitly.
new gives you a dynamic memory allocation(on heap) which will continue to exist and you own it untill you explicitly deallocate it by calling delete.
Failing to call a delete on a newed buffer will lead to Undefined Behaviors usually in the form of. 1 memory leaks.
1 This was discussed here.
when you do a new, OS allocates the memory to the pointer you are assigning it. After your usage is completed you may not require it anymore. But the memory is still marked as "being used" by OS.
Now, when the pointer is declared in a scope of a function or any other block (of {}), it will be deleted (only pointer will be removed) when the execution of the block is over. In such cases the memory that was allocated using new is remained marked "being used" by OS and is not allocated to any other pointer that calls new or to a variable. This causes an orphan block of memory in RAM, that will never be used because its pointer was removed from memory but it will occupy a memory block.
This is called a memory leak. A few of such blocks may make your application unstable as well.
You use delete to free such memory blocks and relieve the OS so that it can be used well for other requests
There is no Garbage Collector in C++, and therefore you are responsible for deallocating the allocated memory. Anyway, the operating system "knows" what memory your program allocated. So when your program exits, the operating system is again responsible for the memory. But if you have a long running C++ program and never call delete noone will help you to get rid of your garbage.
Calling new has allocated memory for the object and it has also arranged for the constructor of that object to be executed.
You could free the memory by calling free(), but you should actually use delete to free memory allocated by new, since this will also cause the objects destructor to be executed.

Deleting memory and effect on data in concerned locations

I am relatively new to programming so this may well sound like a stupid question to you seasoned pros out there. Here goes:
In C++, when I use the delete operator on arrays, I have noticed that the data contained in the released memory locations is preserved. For example:
int* testArray=new int[5];
testArray[3]=24;
cout<<testArray[3]; //prints 24
delete [] testArray;
cout<<testArray[3]; // still prints 24
Subsequently, am I right in assuming that since testArray[3] still prints 42 , the data in the deleted memory location is still preserved? If so, does this notion hold true for other languages, and is there any particular reason for this?
Shouldn't "freed" memory locations have null data, or is "free memory" just a synonym for memory that can be used by other applications, irrespective of whether the locations contain data or not?
I've noticed this is not the case when it comes to non array types such as int, double etc. Dereferencing and outputting the deleted variable prints 0 rather than the data. I also have a sneaking suspicion that I might be using wrong syntax to delete testArray, which will probably make this question all the more stupid. I'd love to hear your thoughts nonetheless.
Once you deallocate the memory by calling delete and try to access the memory at that address again it is an Undefined Behavior.
The Standard does not mandate the compilers to do anything special in this regard. It does not ask the compilers to mark the de-allocated memory with 0 or some special magic numbers.It is left out as the implementation detail for the compilers. Some compiler implementations do mark such memory with some special magic numbers but it is left up to each compiler implementation.
In your case, the data, still exists at the deallocated addresses because perhaps there is no other memory requirement which needed that memory to be re-utilized and the compiler didn't clear the contents of previous allocation(since it is not needed to).
However, You should not rely on this at all as this might not be the case always. It still is and will be an Undefined Behavior.
EDIT: To answer the Q in comment.
The delete operator does not return any value so you cannot check the return status however the Standard guarantees that the delete operator will sucessfully do it's job.
Relevant quote from the C++03 Standard:
Section ยง3.7.3.2.4:
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, render-ing invalid all pointers referring to any part of the deallocated storage.
The data is still there, because when you free, it frees it in the allocation table -- the system would be very slow if it had to zero over all the memory each time free() or delete is called.
This is the same in any language.
I think the non-array types were set to zero because they were in fact statically allocated rather than dynamically allocated.
non-POD data will be altered in a destructor (which might appear as being null-ed in a debugger).
Freed data is just usable, indeed.
You can NOT depend on the data being unaltered after delete. On a related note, debugging malloc's or runtime libraries will frequently reset the data to a specific signature (0xdeadbeef, 0xdcdcdcdc etc) so you can easily spot accesses to deleted memory in a debugger.