The new and delete operators can also be overloaded like other operators in C++. New and Delete operators can be overloaded globally or they can be overloaded for specific classes.
Memory management is a critical aspect of software development, particularly in C++ where manual memory management is prevalent. C++ allows developers to customize memory allocation and deallocation behavior by overloading the new and delete operators. In this article, we'll delve into the concepts of overloading these operators, explore their usage, and discuss best practices.
- If these operators are overloaded using member function for a class, it means that these operators are overloaded only for that specific class.
- If overloading is done outside a class (i.e. it is not a member function of a class), the overloaded ‘new’ and ‘delete’ will be called anytime you make use of these operators (within classes or outside classes). This is global overloading.
Syntax
The syntax for overloading new and delete operators is straightforward. To overload the new operator, you define a new function as a member function of a class or a global function. Similarly, overloading the delete operator involves defining a delete function. Here's the basic syntax:
Overloading the new operator:
void* operator new(std::size_t size) {
// Custom memory allocation logic
}
Here's what each part of this signature means:
- void*: This is the return type of the overloaded new operator. It indicates that the operator returns a pointer to the allocated memory. Since the actual type of the allocated object may vary, void* is used as a generic pointer type that can be safely converted to any other pointer type.
- operator new: This is the keyword indicating that the function is overloading the new operator.
- (std::size_t size): This is the parameter list of the overloaded new operator. It takes a single parameter of type std::size_t, which represents the number of bytes of memory to be allocated. The std::size_t type is an unsigned integer type guaranteed to be able to represent the size of any object in bytes.
When called, the overloaded new operator dynamically allocates a block of memory of the specified size, typically using platform-specific memory allocation functions like malloc or operator new. It then returns a pointer to the beginning of the allocated memory block, which can be used to store the object being created.
Overloading the delete operator:
void operator delete(void* ptr) noexcept {
// Custom memory deallocation logic
}
Here's what each part of this signature means:
- void: This is the return type of the overloaded delete operator. Since the function deallocates memory and doesn't return any value, its return type is void.
- operator delete: This is the keyword indicating that the function is overloading the delete operator.
- (void* ptr): This is the parameter list of the overloaded delete operator. It takes a single parameter of type void*, which represents the pointer to the memory block that needs to be deallocated.
- noexcept: This specifier indicates that the function doesn't throw any exceptions. It's typically added to the declaration of the delete operator to inform the compiler that the function won't throw exceptions during deallocation.
When called, the overloaded delete operator deallocates the memory block pointed to by the ptr parameter. The memory is then freed and can be used for other purposes.
Overloading new Operator
The new operator is used to allocate memory dynamically for objects. By overloading new, developers can customize memory allocation behavior based on their requirements. For instance, they can implement custom memory pools, perform additional error checking, or log memory allocations. Here's a basic example of overloading the new operator:
void* operator new(size_t size) {
void* ptr = malloc(size);
// Perform additional operations if needed
return ptr;
}
or
void* operator new(size_t size) {
std::cout << "Custom new operator: Allocating " << size << " bytes\n";
return ::operator new(size); // Call the default new operator to perform the allocation
}
Overloading delete Operator
The delete operator is used to deallocate memory allocated by new. Overloading delete allows developers to perform custom cleanup operations or implement specialized memory release strategies. Here's a simple example of overloading the delete operator:
void operator delete(void* ptr) noexcept {
// Perform cleanup operations if needed
free(ptr);
}
Complete Example
#include <iostream>
class MyClass {
public:
void* operator new(size_t size) {
std::cout << "Custom new operator: Allocating " << size << " bytes\n";
return ::operator new(size); // Call the default new operator to perform the allocation
}
void operator delete(void* ptr) noexcept {
std::cout << "Custom delete operator: Deallocating memory\n";
::operator delete(ptr); // Call the default delete operator to deallocate the memory
}
};
int main() {
MyClass* obj = new MyClass();
delete obj;
return 0;
}
Output
Custom new operator: Allocating 1 bytes
Custom delete operator: Deallocating memory