Thursday, 20 November 2014

New vs malloc in C++ with examples

New vs malloc in Cpp:

The new and the malloc both are used to allocate the memory in the heap. These are used to allocate the dynamic memory at the runtime of the application.

The main advantage of new over malloc() is that new can allocate memory and  it also constructs objects for the classes.
See the below syntaxes for malloc and new.
MyClass* objMalloc = (MyClass*)malloc(sizeof(MyClass));
MyClass* objNew = new MyClass();

After a run, both objMalloc and objNew will point to areas of memory in the heap that are big enough for a MyClass object.

Data members and methods of MyClass can be accessed using both pointers. The difference is that the MyClass object pointed to by objMalloc is not a proper object because it was never call the constructor.

The certain size of the memory is allocated in the heap using the malloc; it cannot call the constructor of the class. But the new allocate the memory as well as it also constructs an object.

Free vs delete functions in Cpp:
Using the free(), the destructor of the class will not be called. So, cannot call the destructor of the class to clean the memory.
But with delete, the destructor will be called and the object will be properly cleaned up.

new Operator in C++:

The function operator new allocates but does not initialize memory. The new operator has the responsibility of finding in the heap a block of memory that is large enough to hold the amount of memory we request.

As a variation of the new operator, placement new allows us to specify the location to be used. In other words, it allows us to construct an object at a specific, reallocated memory address.
Sytax of the new placement is shown below
new (place) type
new (place) type (initialization list) 

where place must be a pointer and the initialization list provides list of initialization to use when constructing the newly allocated object.

To use the placement new, we should include the new header file, which provides a prototype for this version of new. Then, we use new with an argument that provides the intended address:
#include <new>
class ClsA
{
 char c[100];
 int n;
};
char pchBuff1[200];
char pchBuff2[400];
int main()
{
 ClsA *pA1, *pA2;
 int *pIVal1, *pIVal2;
 pA1 = new ClsA (); // placing a class in heap
 pIVal1 = new int[10];  // placing an int array in heap
 pcA2 = new (pchBuff1) ClsA;  // placing a class in pchBuff1
 pIVal2 = new (pchBuff2) int[10];// placing an int array in pchBuff2
 delete pcA1;
 delete[] pIVal1;
 return 0;

The placement new simply uses the address that is passed to it. It doesn't keep track of whether that location has already been used, and it doesn't search the block for unused memory. This shifts the burden of memory management to the programmer.
delete pcA1;
delete[] pIVal1;

free up the block of memory. However, as we saw in the example, we did not use delete to free the memory used by placement new. Actually, it couldn't. The memory specified by buf is static memory, and delete can be used only for a pointer to heap memory allocated by normal new.

To see a problem of memory management of the previous example, here, a little bit modified version with a constructor using new to make a pointer to a char array and with a destructor which frees the memory occupied by the character array:
using namespace std;
class ClsA
{
 char c[100];
 int n;
 char *str;
public: 
 ClsA ()
        {
  str = new char[10];
 }
 ~A()
        {
  cout << "~ ClsA " << endl;
  delete[] str;
 }
};
char pchBuff1[200];
char pchBuff2[400];
int main()
{
 ClsA *pcA1, *pcA2;
 int *pIVal1, *pIVal2;
 pcA1= new ClsA ();   // placing a class in heap
 pIVal1= new int[10];  // placing an int array in heap
 pcA2= new (pchBuff1) ClsA;  // placing a class in pchBuff1
 pIVal2= new (pchBuff2) int[10];// placing an int array in pchBuff2
 delete pcA1;
 delete[]pIVal2;
 return 0;
}

Output is:
~ ClsA 
Note that the destructor is called at:
delete pcA1; 
But we need to call another destructor for the object created by:
pcA2 = new (pchBuff1) ClsA; 
How can we do that?
Here is the solution: add the following line at the end of the main().
pcA2->~ClsA ();
Then, the output becomes:
~ClsA
~ClsA
In this case we need to call the destructor explicitly. Normally, destructors are called automatically, and this is one of the rare cases that require an explicit call.
I.e. to ensure that the dynamic memory allocated for the object is cleaned up correctly.

No comments: