Contents
Dynamic Memory
new and delete Operators in C++ For Dynamic Memory
Dynamic memory allocation in C/C++ allows programmers to manually manage memory usage, specifically allocating memory on the heap. Unlike stack-allocated memory for local and static variables, dynamic allocation provides the flexibility to allocate and deallocate memory at runtime, which is especially useful for structures like linked lists and trees.
Applications of Dynamic Memory Allocation
One key application of dynamic memory allocation is the ability to handle variable-sized memory requirements, which isn’t feasible with static allocations (except for variable-length arrays). This flexibility is crucial in numerous scenarios, such as creating dynamic data structures.
Differences from Static Memory Allocation
For static variables, such as int a
or char str[10]
, memory management is automatic—allocated and deallocated by the compiler. Conversely, for dynamically allocated memory (e.g., int *p = new int[10]
), the programmer is responsible for deallocation. Failure to do so can lead to memory leaks, where the memory remains allocated until the program terminates.
Memory Management in C++
C uses functions like malloc()
and calloc()
for dynamic memory allocation, along with free()
for deallocation. C++, however, offers a more streamlined approach using the new
and delete
operators.
Using the new
Operator
The new
operator requests memory allocation from the heap. If successful, it returns a pointer to the allocated memory.
Syntax :
pointer-variable = new data-type;
Example:
#include
using namespace std;
int main() {
// Pointer to store the address of allocated memory
int* ptr = new int; // Allocates memory for an integer
*ptr = 10; // Assigns a value to the allocated memory
// Printing the address and value
cout << "Address: " << ptr << endl;
cout << "Value: " << *ptr << endl;
delete ptr; // Deallocating the memory
return 0;
}
Initializing Dynamically Allocated Memory
You can also initialize memory directly upon allocation:
Example:
#include
using namespace std;
struct CustomType {
int value;
CustomType(int v) : value(v) {}
};
int main() {
int* p = new int(42); // Initializes an integer with 42
CustomType* obj = new CustomType(100); // Initializes CustomType
cout << *p << " " << obj->value << endl;
delete p; // Deallocate integer
delete obj; // Deallocate CustomType
return 0;
}
Output:
a + b = 30
a - b = 20
a * b = 125
a / b = 5
a % b = 0
+a = 25
-a = -25
a++ = 25
a-- = 26
Allocating Arrays : You can allocate memory for an array using the new
operator:
Example:
#include
using namespace std;
int main() {
int n = 5;
int* array = new int[n]; // Allocates memory for an array of 5 integers
for (int i = 0; i < n; ++i) {
array[i] = i * 2; // Initializing array elements
}
// Displaying the values
for (int i = 0; i < n; ++i) {
cout << array[i] << " "; // Outputs: 0 2 4 6 8
}
delete[] array; // Deallocate the array
return 0;
}
Output:
a < b : 0
a > b : 1
a <= b: 0
a >= b: 1
a == b: 0
a != b : 1
Handling Memory Allocation Failures : When memory allocation fails, the new
operator throws a std::bad_alloc
exception unless nothrow
is used:
Example:
#include
using namespace std;
int main() {
int* p = new(nothrow) int; // Attempt to allocate memory
if (!p) {
cout << "Memory allocation failed\n";
} else {
*p = 42;
cout << "Value: " << *p << endl;
delete p; // Deallocate memory
}
return 0;
}
Output:
a && b : 1
a || b : 1
!a: 0
The delete
Operator: To free memory allocated with new
, use the delete
operator:
Syntax:
delete pointer-variable; // For single objects
delete[] pointer-variable; // For arrays
Example:
#include
using namespace std;
int main() {
int* singleInt = new int(5);
float* floatValue = new float(10.5);
cout << "Integer: " << *singleInt << endl;
cout << "Float: " << *floatValue << endl;
delete singleInt; // Freeing single integer memory
delete floatValue; // Freeing float memory
int n = 3;
int* intArray = new int[n]; // Allocating an array
for (int i = 0; i < n; ++i) {
intArray[i] = i + 1;
}
cout << "Array values: ";
for (int i = 0; i < n; ++i) {
cout << intArray[i] << " "; // Outputs: 1 2 3
}
delete[] intArray; // Freeing the entire array
return 0;
}
In C++, memory can be dynamically allocated using the new
and delete
operators, while C and C++ also provide the malloc()
and free()
functions for similar purposes. Though they seem to serve the same function, there are key differences between them.
#include
using namespace std;
// Class A
class A {
int a;
public:
int* ptr;
// Constructor of class A
A() {
cout << "Constructor was Called!" << endl;
}
};
// Driver Code
int main() {
// Creating an object of class A using new
A* a = new A;
cout << "Object of class A was created using new operator!" << endl;
// Creating an object of class A using malloc
A* b = (A*)malloc(sizeof(A));
cout << "Object of class A was created using malloc()!" << endl;
// Cleanup
delete a;
free(b); // Note: This does not call the destructor
return 0;
}
Output:
Constructor was Called!
Object of class A was created using new operator!
Object of class A was created using malloc()!
new vs malloc() and free() vs delete in C++
Differences between new
/delete
and malloc()
/free()
in C++
In C++, new
and delete
operators are used for dynamic memory allocation and deallocation, similar to malloc()
and free()
in C. Although they perform similar tasks, there are key differences between them, particularly in how they handle constructors and destructors.
Key Differences: Constructors and Destructors
- malloc(): This is a C library function that can also be used in C++. However, it doesn’t invoke the constructor of a class when allocating memory for an object.
- new: The
new
operator, which is exclusive to C++, allocates memory and also calls the constructor for object initialization.
Below is an example illustrating the difference between new
and malloc()
:
// C++ program to demonstrate `new` vs `malloc()`
#include
using namespace std;
// Class Example
class Example {
int value;
public:
int* pointer;
// Constructor
Example() {
cout << "Constructor called!" << endl;
}
};
int main() {
// Allocating memory with `new`
Example* obj1 = new Example;
cout << "Object created using `new`!" << endl;
// Allocating memory with `malloc`
Example* obj2 = (Example*)malloc(sizeof(Example));
cout << "Object created using `malloc()`!" << endl;
return 0;
}
Output:
Constructor called!
Object created using `new`!
Object created using `malloc()`!
In this example, when using new
, the constructor is called, whereas with malloc
, it is not.
free()
vs delete
- free(): A C library function that deallocates memory but does not call the destructor of a class.
- delete: A C++ operator that not only deallocates memory but also calls the destructor of the class to handle cleanup.
Example:
// C++ program to demonstrate `free()` vs `delete`
#include
using namespace std;
// Class Example
class Example {
int value;
public:
int* pointer;
// Constructor
Example() {
cout << "Constructor called!" << endl;
}
// Destructor
~Example() {
cout << "Destructor called!" << endl;
}
};
int main() {
// Using `new` and `delete`
Example* obj1 = new Example;
cout << "Object created using `new`!" << endl;
delete obj1;
cout << "Object deleted using `delete`!" << endl;
// Using `malloc` and `free`
Example* obj2 = (Example*)malloc(sizeof(Example));
cout << "Object created using `malloc()`!" << endl;
free(obj2);
cout << "Object deleted using `free()`!" << endl;
return 0;
}
Output:
Constructor called!
Object created using `new`!
Destructor called!
Object deleted using `delete`!
Object created using `malloc()`!
Object deleted using `free()`!
In this output, when using delete
, the destructor is called, but with free
, it is not.
More Examples for Understanding
Example 1: Demonstrating Automatic Destructor Call
In this example, we show that the destructor is called automatically when an object goes out of scope, even without explicitly using delete
.
// C++ program to demonstrate automatic destructor call
#include
using namespace std;
// Class Example
class Example {
int value;
public:
int* pointer;
// Constructor
Example() {
cout << "Constructor called!" << endl;
}
// Destructor
~Example() {
cout << "Destructor called!" << endl;
}
};
int main() {
Example obj;
return 0;
}
Output:
Constructor called!
Destructor called!
Here, the destructor is called automatically when return 0
is executed, signaling the end of the program.
To prevent the automatic destructor call, you could replace return 0
with exit(0)
, which terminates the program immediately. Here’s an example of how that would work:
Example 2: Preventing Automatic Destructor Call with exit(0)
// C++ program to prevent automatic destructor call
#include
using namespace std;
// Class Example
class Example {
int value;
public:
int* pointer;
// Constructor
Example() {
cout << "Constructor called!" << endl;
}
// Destructor
~Example() {
cout << "Destructor called!" << endl;
}
};
int main() {
Example obj;
exit(0);
}
Output:
Constructor called!
Here, the destructor is not called because exit(0)
halts the program immediately.
Example 3: Dynamically Allocating an Object with new
// C++ program to demonstrate `new` operator
#include
using namespace std;
// Class Example
class Example {
int value;
public:
int* pointer;
// Constructor
Example() {
cout << "Constructor called!" << endl;
}
// Destructor
~Example() {
cout << "Destructor called!" << endl;
}
};
int main() {
// Dynamically creating an object
Example* obj = new Example;
return 0;
}
Output:
Constructor called!