Lesson 14 | C++ deallocate() function |
Objective | How C++ deallocates memory |
Purpose of C++ deallocate() Function in C++20
In C++20, there isn't a specific deallocate() function in the core language.
There are concepts related to memory deallocation, particularly in the context of custom allocators or the std::allocator_traits which do indeed involve deallocation:
-
std::allocator_traits::deallocate: This is part of the type traits for allocators. It's used to ensure that an allocator type
Alloc
has a deallocation method. Here's how it looks:
- The
std::allocator_traits<Alloc>::deallocate
static member function is used to deallocate memory that was previously allocated. It calls the Alloc::deallocate
function if it exists or falls back to default behavior if not explicitly provided by the allocator.
Here's a basic example of how you might use it:
#include <memory>
#include <vector>
int main() {
std::allocator<int> alloc;
int* p = alloc.allocate(1); // Allocate memory for one int
alloc.deallocate(p, 1); // Deallocate that memory
return 0;
}
In this example:
alloc.allocate(1)
allocates space for one integer.
alloc.deallocate(p, 1)
deallocates that space, where p
is the pointer to the memory and 1
indicates the number of elements that were initially allocated.
-
Purpose:
- Memory Management: The primary purpose of a deallocation function (like
deallocate
in std::allocator_traits
) is to return memory back to the system or the memory pool when it's no longer needed, thus managing resources effectively.
- Custom Allocators: For users implementing custom allocators, providing a
deallocate
method ensures that memory can be managed in a way that's consistent with the standard library containers which use allocators.
- Polymorphic Memory Resources: With C++17's introduction of
std::pmr::memory_resource
, and its continued use in C++20, deallocate
is crucial for managing memory resources in a more flexible, possibly runtime-polymorphic manner.
- C++20 Specifics: While C++20 doesn't introduce a new
deallocate()
function per se, it does enhance and extend the allocator model, particularly with concepts like std::polymorphic_allocator
which can utilize these deallocation methods in more complex scenarios.
In summary, while there isn't a standalone deallocate() function added in C++20, the concept of deallocation is integral to memory management, especially in the context of allocators and container classes, ensuring proper resource management and preventing memory leaks.
The functionality to deallocate memory is closely related to memory management and there isn't one single C++ library that exclusively handles it.
Instead, it's spread across a few key areas:
-
The
<cstdlib>
header: This header provides the C-style memory management functions:
malloc()
: Allocates a block of memory.
free()
: Deallocates memory previously allocated by malloc()
, calloc()
, or realloc()
.
calloc()
: Allocates a block of memory and initializes it to zero.
realloc()
: Resizes a previously allocated block of memory.
-
The
<memory>
header: This header provides more modern C++ memory management facilities:
new
and delete
operators: These operators allocate and deallocate memory for objects, respectively.
std::allocator
: A class template that provides a standard way to allocate and deallocate memory.
std::allocator_traits
: Provides a consistent interface to allocator types, including the deallocate()
member function you mentioned.
- Smart pointers (
std::unique_ptr
, std::shared_ptr
, std::weak_ptr
): These automatically manage memory deallocation, preventing memory leaks.
-
<new>
header: This header defines components that control allocation and deallocation of memory, including how new
and delete
expressions behave.
In summary, deallocation is a core aspect of memory management in C++, and the specific functions and classes you use will depend on your needs and the style of memory management you're employing.
Examine the array deallocation function.
The
deallocate()
function in our dynamic, multidimensional array program deallocates the storage allocated by the operator
new
.
void deallocate(twod& m){
for (int i = 0; i < m.column_size; ++i)
delete [] m.base[i];
delete [] m.base;
m.row_size = 0;
m.column_size = 0;
}
Deallocation works in reverse order to allocation. Each row is deallocated using
delete []
.
It would be a mistake to deallocate
m.base
first, resulting in a system-dependent error. Only after each row of
doubles
is returned to free store can the column of pointers represented by
m.base
be safely deleted.
Next, we will look at the function that determines the maximum element of the array.
Why a destructor is needed
There are many reasons why a destructor may be needed. For example, an object may need to deallocate memory that it had previously allocated or it may need to close a file that it had opened. In C++, it is the destructor that handles deactivation events.
The destructor has the same name as the constructor, but it is preceded by a ~. For example, here is the stack class and its constructor and destructor.
// This creates the class stack.
class stack {
int stck[SIZE];
int tos;
public:
stack(); // constructor
~stack(); // destructor
void push(int i);
int pop();
};
// stack's constructor
stack::stack()
{
tos = 0;
cout << "Stack Initialized\n";
}
// stack's destructor
stack::~stack()
{
cout << "Stack Destroyed\n";
}
Notice that, like constructors, destructors do not have return values.