In chapter 11 of Accelerated C++, the authors present a Vector class emulating the behaviour of std::vector using arrays. They use the allocator class to handle memory management. The role of the uncreate
function is to destroy each element of the array and deallocate the space allocated for the array:
template <class T> void Vec<T>::uncreate() {
if (data) {
// destroy (in reverse order) the elements that were constructed
iterator it = avail;
while (it != data)
alloc.destroy(--it);
// return all the space that was allocated
alloc.deallocate(data, limit - data);
}
// reset pointers to indicate that the Vec is empty again
data = limit = avail = 0;
}
Obviously we need to deallocate allocated space. But it's unclear to me why we need to destroy individual elements as well. What would happen if we only deallocated memory without destroying individual elements?
Basically destructor is about the death of objects and deletion is about the freeing of dynamically allocated memory, but the two actions are often intertwined.
Only deallocate memory when you are truly finished with that memory. If you have more than one pointer to a chunk of memory, then deallocating that chunk makes all pointers to it stale; they are pointing to memory that you are no longer allowed to use. Those pointers are called dangling pointers.
(transitive) To remove from the set of resources put aside for (allocated to) a particular user or purpose. Empty out your locker; it will be deallocated at the end of the day.
Destructors are usually used to deallocate memory and do other cleanup for a class object and its class members when the object is destroyed. A destructor is called for a class object when that object passes out of scope or is explicitly deleted.
The reason is that it'd might get you in trouble. The paragraph 4 from chapter 3.8 (Object lifetime) of C++standard explains why (emphasis mine):
A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
It means it's fine to do it on memory that's occupied by objects with trivial destructor(*) or objects that don't have one at all (such as ints
and the like). But when the memory contains objects of a class that needs to do some work in the destructor (like closing network connections or files, flushing buffers, releasing memory), you'll leak resources (and formaly by the standard, invoke undefined behaviour).
(*) A destructor is trivial if it's compiler generated, is not virtual, and all the non-static members and direct base classes of the class it is member of have trivial destructors.
Destroying the individual elements ensures that their destructors are called and therefore they have a chance to free any resources they own. Simply deallocating the memory would not call the destructor of the object placed in that memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With