How to Use malloc vs new Allocators in C++
-
Use the
new
Operator to Allocate Dynamic Memory in C++ -
Use the
new
Operator andstd::unique_ptr
to Allocate Dynamic Memory in C++ -
Use the
malloc
Function andrealloc
/reallocarray
to Allocate Dynamic Memory
This article will explain several methods of using malloc
vs new
allocators in C++.
Use the new
Operator to Allocate Dynamic Memory in C++
new
is the preferred interface to manage dynamic memory in C++ directly. It constructs an object of the given type and returns the pointer to it. Objects allocated using the new
operator are default initialized, meaning that built-in and compound type objects have garbage values that need to be initialized before use.
Note that new
can be called with multiple notations to suit different needs, but in the following example, we allocate the int
array of size 10
. Thus, the returned pointer stored in the arr1
variable points to the chunk of memory that’s 40
bytes. initPrintIntVector
function is only implemented to demonstrate a practical coding example better. Since we are using a so-called naked pointer, it’s important to free up the allocated memory with the delete
operator before the program exits. Mind though, brackets after the delete
is also necessary to deallocate each location in the array.
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>
using std::cout;
using std::endl;
using std::setw;
using std::vector;
constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;
void initPrintIntVector(int *arr, const int &size) {
std::random_device rd;
std::default_random_engine eng(rd());
std::uniform_int_distribution<int> distr(MIN, MAX);
for (int i = 0; i < size; ++i) {
arr[i] = distr(eng) % 1000;
cout << setw(2) << arr[i] << "; ";
}
cout << endl;
}
int main() {
int *arr1 = new int[SIZE];
initPrintIntVector(arr1, SIZE);
delete[] arr1;
return EXIT_SUCCESS;
}
Output (*random):
8; 380; 519; 536; 408; 666; 382; 244; 448; 165;
Use the new
Operator and std::unique_ptr
to Allocate Dynamic Memory in C++
Even though the new
operator seems to be a fine tool for dynamic memory allocation, it can get quite error-prone in the large codebases with intensive memory manipulations. Namely, deallocation of the memory resources at the right time is quite a hard problem to tackle, and mostly it results in memory leaks or unexpected run-time errors. That’s why the standard library, since the C++ 11 version added smart pointers that automatically delete the memory they point to. std::unique_ptr
is one type of smart pointers, which allows only itself to point to the given object. Note that the allocation is still done using the new
operator, and after the pointer has been used we can exit the program without calling to delete
.
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>
using std::cout;
using std::endl;
using std::setw;
using std::vector;
constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;
void initPrintIntVector(int *arr, const int &size) {
std::random_device rd;
std::default_random_engine eng(rd());
std::uniform_int_distribution<int> distr(MIN, MAX);
for (int i = 0; i < size; ++i) {
arr[i] = distr(eng) % 1000;
cout << setw(2) << arr[i] << "; ";
}
cout << endl;
}
int main() {
std::unique_ptr<int[]> arr2(new int[SIZE]);
initPrintIntVector(arr2.get(), SIZE);
return EXIT_SUCCESS;
}
Output:
985; 885; 622; 899; 616; 882; 117; 121; 354; 918;
Use the malloc
Function and realloc
/reallocarray
to Allocate Dynamic Memory
On the other hand, the C++ code can call the original C-style allocator function - malloc
, which is quite an archaic way of dynamic memory manipulation for modern C++ standards. It’s not the recommended way of allocating objects on the heap, but on the plus side, malloc
provides more flexible functionality.
malloc
is called with a single argument that specifies the sizeof
object and it returns the void*
which should cast to the corresponding type in C++. The one advantage of the malloc
allocated memory is that it can be expanded/shrunk by the realloc
or reallocarray
function. The realloc
function takes the pointer to the object and new size as the arguments, whereas reallocarray
takes the pointer, the number of elements, and each element’s size. Note that if the object memory is expanded, the old stored values stay intact, and newly added elements are uninitialized. Thus, the following example prints out the expanded arr3
elements for demonstration purposes only, and it should not be the case in the real-world program.
#include <iomanip>
#include <iostream>
#include <random>
#include <vector>
using std::cout;
using std::endl;
using std::setw;
using std::vector;
constexpr int SIZE = 10;
constexpr int NEW_SIZE = 20;
constexpr int MIN = 1;
constexpr int MAX = 1000;
void initPrintIntVector(int *arr, const int &size) {
std::random_device rd;
std::default_random_engine eng(rd());
std::uniform_int_distribution<int> distr(MIN, MAX);
for (int i = 0; i < size; ++i) {
arr[i] = distr(eng) % 1000;
cout << setw(2) << arr[i] << "; ";
}
cout << endl;
}
void printIntVector(int *arr, const int &size) {
for (int i = 0; i < size; ++i) {
cout << setw(2) << arr[i] << "; ";
}
cout << endl;
}
int main() {
int *arr3 = static_cast<int *>(malloc(SIZE * sizeof(int)));
// int *arr3 = static_cast<int *>(malloc(SIZE * sizeof *arr3));
// int *arr3 = static_cast<int *>(malloc(sizeof(int[SIZE])));
initPrintIntVector(arr3, SIZE);
arr3 = static_cast<int *>(reallocarray(arr3, NEW_SIZE, sizeof(int)));
// arr3 = static_cast<int *>(realloc(arr3, NEW_SIZE * sizeof(int)));
printIntVector(arr3, NEW_SIZE);
free(arr3);
return EXIT_SUCCESS;
}
Output:
128; 346; 823; 134; 523; 487; 370; 584; 730; 268;
128; 346; 823; 134; 523; 487; 370; 584; 730; 268; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook