new operator in C++ for dynamic memory

new operator in c++

In this blog post tutorial, you will learn about all the concepts related to the C++ new operator with programming examples. But before explaining the new operator and its use in C++ programming. I want to explain the requirement of dynamic memory in programming.

The requirement of dynamic memory depends on your platform and the project. I have seen many embedded firmware projects where dynamic memory was not allowed and some used dynamic memory very rarely.

There is no golden rule, on when to use the dynamic memory and when not to use it. it depends on the requirement and platform. I have used dynamic memory in many projects.

In one of my POS (point of sale) projects where we needed to parse the XML response of the payment gateway. But before the parsing, we needed to store all XML response data. The raw response data was huge and the size was dynamic. So here problem was that to store the data we could not reserve the fixed stack memory size because the size of the data was dynamic and it can be dangerous if the data size was bigger than the reserved memory.

So here we have used dynamic memory to solve our problem. We adjust the buffer size according to the raw response data. But you must remember that you have to destroy the allocated dynamic memory.

So if your platform allows then you can use the dynamic memory in the below situation but remember it is not a mandatory and golden rule. You should only use the dynamic memory when you find it useful otherwise, use a stack-allocated memory.

1. When the array is too large to be placed on the stack (typical stack size is 1 MB, so anything bigger than 50-100KB should better be dynamically allocated, or you’re risking a crash).

2. When the lifetime of the buffer must live out of the scope where it is created (stack memory gets destroyed when the function ends).

3. When you’re building a structure (like array or graph) of a size that is unknown (i.e. may get big), dynamically changes, or is too hard to precalculate.

 

Now next question comes, how we can allocate the dynamic memory? or in other words how to create an array of dynamic size at run time?

The answer to the above question is very simple, we can allocate and then deallocate memory dynamically using the new and delete operators respectively. If you want you can use the memory management functions malloc, calloc,..etc but not advisable in C++.

You must remember, In C++, we need to deallocate the dynamically allocated memory manually after we have no use for it.

Now it’s time to learn “new operator” and “delete operator” with programming examples. We will see how to allocate memory at the run time using the new operator in C++.

 

C++ new operator (new-expression):

The new-expression attempts to create and initialize an object and the type of that object is the allocated type. This type shall be a complete object type, but not an abstract class type or array thereof.

Note: Because references are not objects, references cannot be created by new-expressions.

 

Generally, we use the following syntax to allocate the memory using the new expression.

T * variable = new T; // allocate one element of type T

T* variable = new T[n]; // allocate n elements of type T

Examples,

int* ptr1 = new int; // allocate memory for one integer

int* ptr2 = new int[10]; // allocate memory for 10 integers

 

 

Let’s consider the following code example allocates memory for an integer and then free it after its use ( assigning a value it printing it).

#include <iostream>
using namespace std;

int main()
{
    // declare an int pointer
    int* ptr = nullptr;


    // dynamically allocate memory
    ptr = new int;


    // assigning 45 to the memory
    *ptr = 45;


    cout << *ptr << endl;


    // deallocate the memory
    delete ptr;

    return 0;
}

Output: 45

 

What will happen if not allocated dynamic memory to the pointers?

Here I am only discus on the behalf of dynamic memory allocation. Let’s consider the following example to understand “what will happen if not allocated valid memory to the pointers”.

#include <iostream>
using namespace std;

int main()
{

    int* piValue  = nullptr;

    (*piValue) = 276; // Assigned the value

    cout << "Value of integer pointer = " << *piValue << endl;


    return 0;
}

 

You are able to compile this code successfully but when you will run it, it shows undefined behavior. In C++, indirection through a null pointer shows undefined behavior. In most cases, it will crash your application.

 

But you can solve this problem to assign a valid memory. After assigning a valid memory your code will work fine. But you have to deallocate the memory. In the below portion I will also discuss the delete operator and its uses.

#include <iostream>
using namespace std;

int main()
{
    int* piValue  = nullptr;

    // Allocate the memory using new operator
    piValue = new int;

    (*piValue) = 276; // Assigned the value

    cout << "Value of integer pointer = " << *piValue << endl;

    return 0;
}

Output: 276

 

 

Some important concepts related to the new operators:

 

1. Objects created by a new-expression have dynamic storage duration. It means the lifetime of such an object is not necessarily restricted to the scope in which it is created. Example,

#include<iostream>

using namespace std;

int *alloc_int()
{
    //returning allocated memory
    // not only bounded to this function
    return new int;
}

int main()
{
    int *ptr = alloc_int(); //valid

    *ptr = 10;

    cout << *ptr;

    delete ptr;

    return 0;
}

 

2. You can initialize the object created by a new-expression. Example,

//Dynamically allocated int with value 9
int* p = new int(9);

//Dynamically allocated float with value 27.6
float* p1 = new float(27.6);

 

3. When the allocated object is not an array, the result of the new-expression is a pointer to the object created. Example,

new char; >> Result pointer to char

new int; >> Result pointer to int

new float; >> Result pointer to float

new T; >> Result pointer to T

 

4.We can use C++ new and delete operator for arrays. When the allocated object is an array, the new-expression yields a pointer to the initial element (if any) of the array. Example,

new char[10]    >>  Have type char* 

new int[10]    >>   Have type int* 

new int[i][10] >>   Have type int (*)[10]

 

5. When allocating a multidimensional array, all dimensions except the first must be constant expressions that evaluate positive values. The leftmost array dimension can be any expression that evaluates to a positive value. Example,

int n = 42;

/*
 Valid: It is well-formed because 
 n is the expression of a noptr-new-declarator.
*/
new float[n][5]; 

/*
 Invalid: It is ill-formed because 
 n is not a constant expression.
*/
new float[5][n];

 

6.The initializer is mandatory when you are creating an array of unknown bounds. The allocated object is an array with n elements, where n is determined from the number of initial elements supplied in the initializer. Example,

/*
creates an array of type int[3]
*/
int* p = new int[]{1,2,3};

 

7. The type-id can be a cv-qualified type, in which case the object created by the new-expression has a cv-qualified type. But personally, I have never used it. Example,

#include<iostream>

struct Test
{
    Test()
    {
        std::cout << "construct the object\n";
    }
    ~Test()
    {
        std::cout << "destruct the object\n";
    }
};

int main()
{
    //create the object
    const Test* ptr1 = new const Test;

    //destroy the object
    delete ptr1;

    return 0;
}

Output:

construct the object
destruct the object

 

8. Use the delete operator to deallocate the memory allocated by the new operator. Use the delete[] operator to delete an array allocated by the new operator.

9The new operator can’t be used to allocate a function, but it can be used to allocate pointers to functions. The following example allocates an array of 10 pointers to functions (taking no argument and returning int).

/*
 Allocates an array of 10 pointers to 
 functions (taking no argument and returning int).
*/
int (**p)() = new (int(*[10])());

 

delete operator in C++:

The delete-expression operator destroys an object or array of objects created by a new expression. Once you no longer need to use an object or array of objects that you have declared dynamically, you have to deallocate the memory occupied by the object or array of objects. If you forget to delete the allocated memory, it could be the cause of the memory leak.

Syntax of delete operator in C++:

The following is the general syntax of delete expression.

1. ::opt delete cast-expression

2. ::opt delete [ ] cast-expression

1. Destroys one non-array object created by a new-expression.

2. Destroys an array created by a new[]-expression

Remark: You should remember that the uses of new and delete should be compatible. You should pair new with delete and new [] with delete []. Examples,

Case 1. Use of delete for object:

int* ptr1 = new int;

//use ptr1 in your code


// deallocate the ptr1 after use
delete ptr1;

Case 2. Use of delete [] for an array of objects:

int* ptr2 = new int[100];

//use ptr2[] in your code


// deallocate the ptr2 after use
delete [] ptr2;

 

I will cover the delete operator in another blog post in detail. Now lets come to the topic  “new operator” and see some programming examples for a better understanding.

 

Dynamic memory allocation for an array using new operator in C++:

The following code example allocates a character array and then frees them. As we know when the allocated object is an array, the new-expression yields a pointer to the initial element of the array. So in the below code new expression returns the pointer to the char. See the below-mentioned image where pcBuffer (pointer to char) is pointing to the first element of the array and the size of the array is 10.

https://aticleworld.com/

#include <iostream>
using namespace std;

int main()
{
    // allocated memory for array of character
    char *pcBuffer = new char[10];

    // Assigned value to the char array
    for(int index = 0; index <= 9; index++)
    {
        pcBuffer[index] = index+48;
    }

    //print assigned value
    for(int index =0; index <= 9; index++)
    {
        cout<<pcBuffer[index]<<endl;
    }

    //delete the allocated memory
    delete [] pcBuffer;

    return 0;
}

 

Output: 0 1 2 3 4 5 6 7 8 9

 

Let’s see another example where I am using a double pointer for dynamic memory allocation. In the below example, I am using the new expression twice the first time for the  array of char * and second times for the array of char.

Using a double pointer for dynamic memory allocation

#include <iostream>
using namespace std;

#define COLOUMN  3
#define ROW      3

int main()
{
    //Create an array of char pointer
    char **pcBuffer = new char*[ROW];


    for(int iCol =0 ; iCol <COLOUMN; iCol++)
    {
        //create an array of char
        pcBuffer[iCol]= new char[COLOUMN];
    }


    for(int iRow =0; iRow<ROW; iRow++)
    {
        for(int iCol =0 ; iCol< COLOUMN; iCol++)
        {
            //assigned the value to the allocated memory
            pcBuffer[iRow][iCol]=(iRow+iCol)+48;
        }
    }

    for(int iRow =0; iRow<ROW; iRow++)
    {
        for(int iCol =0 ; iCol< COLOUMN; iCol++)
        {
            //print the assigned value
            cout<<pcBuffer[iRow][iCol]<<endl;
        }
    }

    // first free the char *
    for(int iCol =0 ; iCol< COLOUMN; iCol++)
    {
        delete [] pcBuffer[iCol];
    }

    //in the last double pointer
    delete [] pcBuffer;

    return 0;
}

Output: 

0 1 2
1 2 3
2 3 4

 


How to initialize the dynamic array with default (0) value in C++?

Each element of a “T” type array can be initialized with 0 using the empty parenthesis. This is explicitly permitted by ISO C++ 03.

#include <iostream>
using namespace std;

int main()
{
    int *piValue = NULL;

    //implement empty parenthesis
    piValue = new int[10]();

    for(int index = 0; index < 10; index++)
    {
        cout<< "Array value = "<< *(piValue+index)<<endl;
    }

    delete [] piValue;

    return 0;
}

Output:

initialize dynamic array with 0 in C++

 

 

 

 

 

Create a class object using the new operator in C++:

Using the C++ new operator we can create the object and we can destroy it using the delete operator. See the following example where I am creating an Animal class object using the new keyword.

#include <iostream>
using namespace std;

class Animal
{
public:
    Animal():m_uiSpeed(30)
    {

    }
    ~Animal()
    {
        cout << "Object destroyed\n";
    }
    unsigned int m_uiSpeed;
};

int main()
{
    // create object using the new keyword
    Animal *pCat = new Animal();

    cout <<"Default Speed of Cat = "<<pCat->m_uiSpeed<<endl;

    //assigned the value to member variable
    pCat->m_uiSpeed = 50;

    cout <<"Updated Speed of Cat = "<<pCat->m_uiSpeed<<endl;

    //destroy the object
    delete pCat;

    return 0;
}

Output:

Default Speed of Cat = 30
Updated Speed of Cat = 50
Object destroyed

In this program, I have created an Animal class that has a public attribute m_uiSpeed. I have initialized m_uiSpeed to 30 in the constructor Animal() and printed its value. After printing the value I am assigning a value to m_uiSpeed.




Why should we use the new operator in C++?

Let’s some situations where we need to use the new operator in C++ programming.

1.You should use new when you wish an object to remain in existence until you delete it. Let’s see the below example to understand the mentioned expression.

#include <iostream>
using namespace std;

class Animal
{
public:
    unsigned int m_uiSpeed;
};

int main()
{
    int iSpeedRequired = 0;

    cout<< "Enter 1 to get the Speed  = ";

    cin>>iSpeedRequired;

    if(1 == iSpeedRequired)
    {
        Animal cat;
        cat.m_uiSpeed = 100;

        cout<<"Speed = "<<cat.m_uiSpeed<<endl;
    }
    else
    {
        cout<<"Entry is wrong"<<endl;
    }

    cout<<"Speed = "<<cat.m_uiSpeed<<endl;

    return 0;
}

Output:

Why should we use the new operator in C++?

 

 

 

In the above code, we have created an object “cat”.  The cat object is created is the stack, so when control comes out the outside of its scope it will destroy. So when you will try to access the “cat” object beyond its scope, you will get the compiler error.

We can solve the above problem to create the object using the new operator because memory allocated by the new does not destroy automatically when goes beyond the scope. It is the responsibility of the developer to destroy the allocated memory explicitly using the delete operator.

2.You cannot change the size of a stack array at run-time. So where you need an array of the undetermined size you must use the new operator.

void fun(int size)
{
    int* pointArray = new int[size];
    
    //code...
    
    delete [] pointArray;
}

 

3. When the array is too large to be placed on the stack.

 

Why should I use new instead of malloc()?

Each has there own advantage but let’s see some scenarios where we need to use the new operator instead of malloc().

1. Constructors/destructors:

The class constructor is invoked by the new operator but not by the malloc. Similarly, destructor invoked by delete, not by the free.

#include <iostream>
using namespace std;

class Animal
{
public:

    unsigned int m_uiSpeed;
    Animal();
    ~Animal();
};

// constructor
Animal::Animal()
{
    cout<<"\nCreating Object\n";
}

// destructor
Animal::~Animal()
{
    cout<<"\nDeleting Object\n";
}

int main()
{
    //Creating object using new operator
    Animal *cat = new Animal();

    delete cat;

    return 0;
}

Output:

Creating class object with new operator

 

 

 

2. Type safety:

The malloc() returns a void* which is not type-safe. new T returns a pointer to T.

3. Overridability:

“new” is an operator that can be overridden by a class, while malloc() is not overridable on a per-class basis.




Exception handling of the new operator:

When the new operator request for the memory then if there is a free memory is available then it returns a valid address, either it throws bad_alloc exception.

Let’s see an example where we will catch the bad_alloc exception through a try-catch block.

#include <iostream>

using namespace std;


int main()
{
    int *piValue = nullptr;

    try
    {
        piValue = new int[9999999999999]; // allocate huge amount of memory
    }
    catch(...)
    {
        cout<<"Free memory is not available"<<endl;

        return -1;
    }

    delete []piValue;

    return 0;
}

Output:

new expression

 

 

To avoid the exception throw we can use “nothrow” with the new operator. When we are used “nothrow” with the new operator, it returns a valid address if it is available otherwise it returns a null pointer.

But here one point needs to remember we need to include file <new> for the use of “nothrow” with the new operator.

#include <iostream>
#include <new>

using namespace std;

int main()
{
    // We are using nothrow here.
    int *piValue = new(nothrow)int[999999999999999];

    if(!piValue)
    {
        cout<<"Free memory is not available"<<endl;
    }
    else
    {
        cout<<"Free memory available"<<endl;
        delete []piValue;
    }

    return 0;
}

Output:

new operator

 

 

 

 

 

What is the difference between the new operator and malloc()?

Let’s see some common differences between malloc and new operator. I have already covered this interesting topic in another blog post. If you want you can check this post “malloc vs new“.

malloc new
malloc() is a library function that takes a number (of bytes) as its argument. new is an operator that takes a type and (optionally) a set of initializers for that type as its arguments.
It returns a void* pointing to uninitialized storage which is type unsafe. Returns a pointer to an (optionally) initialized object of its type which is type-safe.
It does not call the constructor. Calls the constructor.
Returns 0 or NULL on failure. It throws bad_alloc exception on failure.
It cannot be overridden. It can be overridden.
memory allocated by malloc() is deallocated by free(). Objects created by new are destroyed by delete.
Need to pass the size. Size is calculated by the compiler.

 

Placement new Operator in C++:

Before explaining the “placement new” let’s first see the general syntax of the new expression.

::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt

Here, the new-placement syntax is used to supply additional arguments to an allocation function; such an expression is called a placement new-expression. Placement new allows you to construct an object in memory that’s already allocated.

The “placement new”, is a technique to call the class constructor on an already-allocated memory, by specifying an already allocated memory location.

It can be useful when you need to construct multiple instances of an object.  You can use this technique for optimization. Using this you will get a new instance of the object without reallocating the memory. But you should remember “placement new” could be introduced a serious bug in your code. Because if you are using the “placement new” all responsibility will be yours, the compiler will not check the alignment and validity of the memory.

Remark: There is no a “placement delete”. You are also solely responsible for destructing the placed object. This is done by explicitly calling the destructor:

Let’s see an example of how to use “placement new”.

class Test
{
public:
    Test() {}
    ~Test() {}

};


void myTestFun()
{
    /*
      Statically allocate the storage with automatic storage duration
      which is large enough for any object of type `Test`.
    */
    alignas(Test) unsigned char buf[sizeof(Test)];


    /*
    Construct a `Test` object, placing it directly into your
    pre-allocated storage at memory address `buf`.
    */
    Test* tptr = new(buf) Test; //

    /*
    You must **manually** call the object's destructor
    if its side effects is depended by the program.
    Leaving this block scope automatically deallocates `buf`.
    */
    tptr->~Test(); //
}

 

 

Some important questions related to new and delete you should know:

Q-1: Can I use delete twice on the same pointer?

Ans:

No, you must not do this. For example, the following code shows undefined behavior:

void yourCode()
{
    int* p = new int(2);
    delete p;
    delete p;  // UB (Undefined Behavior)!
}

 

Q-2: Can I free() pointers allocated with new?

Ans:

No. You must only use delete to destroy the memory allocated by “new”. The delete operator calls the destructor.

 

Q-3: Can I use delete pointers allocated with malloc()?

Ans:

No. You must only use free() to release the memory allocated by malloc().

 

Q-4: Why should I use new instead of malloc()?

Ans:

Already explained above.

 

Q-5: Do I need to check for null before deleting the pointer with the delete operator?

Ans:

No. The C++ language guarantees that delete p will do nothing if p is null. But if you overload the delete operator, it may no longer be “safe” to delete NULL.

 

Q-6: How do I deal with memory leaks?

Ans:

The objects created by new-expressions persist until you do not deallocate them with delete-expressions. I have already written a blog post on memory leaks, if you want you can refer to it  “What is a memory leak and how you can avoid it“.

In C/C++ programming generally, a memory leak occurs when the pointer is lost its original allocated value. It becomes the cause of the memory leak because the allocated object becomes unreachable and cannot be deallocated.

Let’s see some common scenarios where the pointer is lost its original value:

1.Assign the different values to the pointer before calling the delete expression. Example,

// Dynamically allocated int with value 6
int* ptr = new int(6);


// Assign null to pointer befoer calling delete expression.
ptr = nullptr; // memory leak

 

2.An exception occurs before deleting the memory. Example,

void f()
{
   //Dynamically allocated in with value 27
   int* ptr = new int(27);

   g();      // may throw

   delete p; // okay if no exception
} // memory leak if g() throws exception

 

3. pointer goes out of scope.

void f()
{
   //local pointer dead once control goes out of the scope.
   // Allocated memory remain blocked when pointer dead.
    int* p = new int(7);

} // memory leak

 

 

Recommended Articles for you:

3 comments

Leave a Reply

Your email address will not be published. Required fields are marked *