Table of contents
1.
Introduction
2.
How is it different from memory allocated to normal variables?
3.
How is memory allocated/deallocated in C++?
4.
Syntax
5.
Parameters
6.
Return Value
6.1.
1. Pointer to the allocated memory
6.2.
2. nullptr on failure
6.3.
3. Type of the returned pointer
7.
Normal Array Declaration vs Using new
7.1.
1. Normal Array Declaration
7.2.
2. Using "new" for Dynamic Array Allocation
8.
What if enough memory is not available during runtime?
8.1.
1. std::bad_alloc exception
8.2.
2. Checking the return value of "new"
9.
Frequently Asked Questions
9.1.
Can I use "new" to allocate memory for objects?
9.2.
Is it necessary to deallocate memory allocated with "new"?
9.3.
Can I allocate memory dynamically for multidimensional arrays using "new"?
10.
Conclusion
Last Updated: Oct 14, 2024
Easy

New Operator In C++

Author Rinki Deka
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

In C++, the "new" keyword helps dynamically allocate memory for variables or arrays while the program is running. It lets you decide the size of objects or arrays when the program is actually running, not just when you first write the program. This is very helpful when you don't know in advance how much memory you will need or if this amount might change as the program works. With "new," you can efficiently manage memory resources & create dynamic data structures according to your program's needs. 

New Operator In C++

In this article, we will discuss dynamic memory allocation using "new" in C++, understand its syntax & parameters, & compare it with traditional array declaration. We will also discuss how C++ handles situations when sufficient memory is not available during runtime.

How is it different from memory allocated to normal variables?

When you create a normal variable in C++, like an integer or a character, the compiler automatically sets aside memory for it in an area called the stack or static memory. The amount of memory it uses depends on the type of variable and doesn't change. For example, if you make an integer variable by writing "int x;", the compiler always reserves 4 bytes of memory for it.

However, when you use the "new" keyword to allocate memory, it comes from a different place called the heap. This is a big pool of memory that the operating system manages. The size of the memory you get with "new" is decided when the program is running, based on what your program needs at that moment. You can ask for different amounts of memory as your program requires.

Another important difference is how long the memory is kept. Memory for normal variables is cleaned up automatically when the variable is no longer needed, or when the program ends. But the memory you've allocated with "new" stays around until you specifically free it up using the "delete" keyword. If you forget to use "delete," that memory stays used up, which can cause problems called memory leaks where memory is wasted even when it's not being used anymore.

How is memory allocated/deallocated in C++?

In C++, memory allocation & deallocation for dynamic variables are done using the "new" & "delete" keywords, respectively.

To allocate memory dynamically, you use the "new" keyword followed by the data type you want to allocate memory for. For example, to allocate memory for an integer variable dynamically, you would write:

int* ptr = new int;


Here, "ptr" is a pointer variable that stores the address of the newly allocated memory. The "new" keyword returns the address of the allocated memory, which is then assigned to the pointer.

You can also allocate memory for arrays dynamically using "new". To allocate memory for an array of integers, you would write:

int* arr = new int[size];


In this case, "size" is a variable that specifies the number of elements in the array. The "new" keyword allocates a block of memory that can accommodate "size" integers & returns the address of the first element.

When you no longer need the dynamically allocated memory, it's important to deallocate it using the "delete" keyword. To deallocate memory pointed to by a single pointer, you use:

delete ptr;


To deallocate memory allocated for an array, you use the "delete[]" syntax:

delete[] arr;


It's very important to use the correct form of "delete" based on whether you allocated memory for a single variable or an array. Using the wrong form can lead to undefined behavior.

Syntax

The syntax for using the "new" keyword in C++ is very easy. Let’s see the syntax for allocating memory for a single variable:

datatype* pointer_name = new datatype;


- `datatype`: The data type of the variable you want to allocate memory for (e.g., int, float, double).
 

- `pointer_name`: The name of the pointer variable that will store the address of the allocated memory.
 

For example, to allocate memory for a single integer variable:

int* ptr = new int;


When allocating memory for an array, the syntax is slightly different:

datatype* pointer_name = new datatype[size];


- `datatype`: The data type of the elements in the array.
 

- `pointer_name`: The name of the pointer variable that will store the address of the allocated memory.
 

- `size`: The number of elements in the array.

 

For example, to allocate memory for an array of 10 integers:

int* arr = new int[10];


To deallocate the memory, you use the "delete" keyword followed by the pointer variable:

delete pointer_name;       // For a single variable
delete[] pointer_name;     // For an array


It's important to note that you should only deallocate memory that was previously allocated using "new". Attempting to deallocate memory that was not dynamically allocated or deallocating the same memory twice can lead to undefined behavior.

Parameters

When we are using the "new" keyword in C++, we can specify parameters to initialize the dynamically allocated variable or array. 

Let’s discuss the different ways to use parameters with "new":


1. Allocating a single variable with default initialization

datatype* pointer_name = new datatype;


In this case, the allocated variable is default-initialized. For example, if you allocate an integer using `int* ptr = new int;`, the integer will be default-initialized to 0.


2. Allocating a single variable with a specified value

datatype* pointer_name = new datatype(value);


Here, you can provide an initial value for the allocated variable. For example, `int* ptr = new int(42);` allocates an integer & initializes it with the value 42.


3. Allocating an array with default initialization

datatype* pointer_name = new datatype[size];


This syntax allocates an array of the specified size, & each element of the array is default-initialized. For example, `int* arr = new int[5];` allocates an array of 5 integers, & each integer is default-initialized to 0.


4. Allocating an array with a specified initial value

datatype* pointer_name = new datatype[size] {value1, value2, ...};


In this case, you can provide a list of initial values for the elements of the array. The number of values provided should not exceed the specified size of the array. For example, `int* arr = new int[3] {1, 2, 3};` allocates an array of 3 integers & initializes them with the values 1, 2, & 3.


It's important to note that when you allocate memory dynamically using "new," you are responsible for deallocating that memory using "delete" when it is no longer needed. If you don't deallocate the memory it can result in memory leaks.

Return Value

Whenever we use the "new" keyword in C++, it returns a pointer to the newly allocated memory. The return value of "new" is of the same data type as the pointer you are assigning it to. 

Let’s see a few important points about the return value of "new":

1. Pointer to the allocated memory

The "new" keyword returns a pointer that points to the beginning of the allocated memory block. This pointer can be assigned to a pointer variable of the appropriate data type. For example:

int* ptr = new int;


In this case, "new int" allocates memory for an integer & returns a pointer to that memory, which is then assigned to the pointer variable "ptr".

2. nullptr on failure

If the memory allocation fails due to insufficient memory or other reasons, "new" returns a special value called "nullptr". It is a good practice to check the return value of "new" against nullptr to handle allocation failures gracefully. For example:

int* ptr = new int;
if (ptr == nullptr) {
    // Handle memory allocation failure
    // ...
}


By checking if the pointer is nullptr, you can take appropriate action, like displaying an error message or terminating the program.

3. Type of the returned pointer

The type of the pointer returned by "new" matches the data type you specified. For example, if you allocate memory for an integer using `new int`, the returned pointer will be of type `int*`. Similarly, if you allocate memory for a floating-point number using `new double`, the returned pointer will be of type `double*`.

It's important to store the returned pointer in a variable of the appropriate type to avoid type mismatches & to ensure proper memory management.

Normal Array Declaration vs Using new

In C++, you can declare arrays in two ways: using normal array declaration syntax or using the "new" keyword for dynamic memory allocation. Let's compare these two approaches:

1. Normal Array Declaration

int arr[5];

 

  • The size of the array is fixed at compile time & cannot be changed during runtime.
     
  • The memory for the array is allocated on the stack.
     
  • The memory is automatically deallocated when the array goes out of scope.
     
  • The size of the array must be known at compile time.

2. Using "new" for Dynamic Array Allocation

int* arr = new int[5];

 

  • The size of the array can be determined at runtime & can be changed dynamically.
     
  • The memory for the array is allocated on the heap.
     
  • The memory remains allocated until you explicitly deallocate it using the "delete[]" keyword.
     
  • The size of the array can be specified using a variable or an expression.
     

Let’s discuss some of the key differences between normal array declaration & using "new":
 

1. Memory Allocation:

  • Normal array declaration allocates memory on the stack, which is limited in size.
     
  • "new" allocates memory on the heap, which is larger & can accommodate dynamic memory requirements.
     

2. Array Size:

  • With normal array declaration, the size of the array is fixed at compile time & cannot be changed during runtime.
     
  • Using "new," the size of the array can be determined dynamically at runtime, allowing for flexibility.
     

3. Scope & Lifetime:

  • Arrays declared using normal syntax have automatic storage duration & are destroyed when they go out of scope.
     
  • Arrays allocated using "new" have dynamic storage duration & persist until explicitly deallocated using "delete[]".
     

4. Syntax:

  • Normal array declaration uses square brackets `[]` to specify the size of the array.
     
  • Dynamic allocation with "new" uses the "new" keyword followed by the data type & square brackets `[]` to specify the size.


Let’s see an example showing the difference clearly : 

// Normal array declaration
int normalArr[5] = {1, 2, 3, 4, 5};
// Dynamic array allocation using "new"
int size = 5;
int* dynamicArr = new int[size];
for (int i = 0; i < size; i++) {
    dynamicArr[i] = i + 1;
}
// Deallocate the dynamically allocated array
delete[] dynamicArr;

 

In the above example, `normalArr` is declared using the normal array declaration syntax with a fixed size of 5, while `dynamicArr` is allocated dynamically using "new" with a size determined by the `size` variable.

What if enough memory is not available during runtime?

When you use the "new" keyword to allocate memory dynamically in C++, there is a possibility that the memory allocation may fail if there is not enough memory available during runtime. In such cases, C++ provides mechanisms to handle the situation. Let's discuss what happens & how you can deal with insufficient memory during runtime.

1. std::bad_alloc exception

By default, when memory allocation fails using "new," C++ throws an exception of type `std::bad_alloc`. This exception is defined in the `<new>` header & indicates that the memory allocation request could not be fulfilled. If you don't catch & handle this exception, it will propagate up the call stack & eventually terminate the program if not caught.

Example of how you can catch & handle the `std::bad_alloc` exception:

try {
    int* ptr = new int[1000000000]; // Attempt to allocate a large amount of memory
    // ...
} catch (const std::bad_alloc& e) {
    std::cout << "Memory allocation failed: " << e.what() << std::endl;
    // Handle the exception, e.g., display an error message or take alternative action
}


In this example, if the memory allocation fails, the `std::bad_alloc` exception will be thrown & caught by the `catch` block. You can then handle the exception appropriately, such as displaying an error message or taking alternative actions.

2. Checking the return value of "new"

Another way to handle memory allocation failures is to check the return value of "new" against nullptr. If "new" fails to allocate memory, it returns a nullptr. You can use this to detect allocation failures & take appropriate action.

For example : 

int* ptr = new (std::nothrow) int[1000000000]; // Attempt to allocate a large amount of memory
if (ptr == nullptr) {
    std::cout << "Memory allocation failed." << std::endl;
    // Handle the failure, e.g., display an error message or take alternative action
} else {
    // Memory allocation succeeded, use the allocated memory
    // ...
    delete[] ptr; // Remember to deallocate the memory when done
}


In this case, we use the `std::nothrow` parameter with "new" to indicate that we don't want an exception to be thrown if the allocation fails. Instead, "new" will return a nullptr. We then check if `ptr` is nullptr & handle the failure accordingly.

It's important to note that in both approaches, you should handle memory allocation failures very diligently. Depending on your program's requirements, you may choose to display an error message, log the failure, or take alternative actions like using a fallback mechanism or terminating the program.

Frequently Asked Questions

Can I use "new" to allocate memory for objects?

Yes, you can use "new" to allocate memory for objects. Simply use the class name instead of a primitive data type.

Is it necessary to deallocate memory allocated with "new"?

Yes, it is crucial to deallocate memory allocated with "new" using the "delete" keyword to avoid memory leaks.

Can I allocate memory dynamically for multidimensional arrays using "new"?

Yes, you can allocate memory for multidimensional arrays using "new". You need to use multiple sets of square brackets to specify the dimensions.

Conclusion

In this article, we have learned about the "new" keyword in C++ & how it allows us to allocate memory dynamically during runtime. We discussed the differences between memory allocation for normal variables & dynamically allocated memory using "new". We also covered the syntax & parameters for using "new" & understood the return value it provides. Moreover, we compared normal array declaration with dynamic array allocation using "new". Lastly, we discussed how to handle situations when enough memory is not available during runtime by catching exceptions or checking the return value of "new"

You can also check out our other blogs on Code360.

Live masterclass