C++ how to use placement new and placement delete operators


Placement new and placement delete operator in C++

Using the new operator we can allocate storage for the data in the heap,but there is certain disadvantage here.The place(address) where the storage will be allocated is not known by the compiler before hand-the storage is in heap but the specific address is not known- the storage allocated can be anywhere! To overcome this limitation C++ provide another technique,also known as placement new operator.Using placement new operator we can place the object in a specific location where the programmer wants it to reside.In other words,with placement new operator the address of the storage where the object will be created can be known before hand.This feature becomes useful while working in an environment with limited resources.

To implement the placement feature the programmer has to pass the address of the memory as an argument to the new operator.Taking the address of the argument the compiler will make the object reside in that location.So placement new operator is a new operator that accepts an argument:which is the address of the memory.Note placement new returns that same address which is passed as the argument.The code below shows the syntax of the placement new operator.

 
int *i=new(&Address) int(0) ; ///Address is the address of the location
 

In the code an address ‘Address‘ is passed to the new operator and that address is also returned by the new operator and is assigned to ‘i‘ pointer.Note the value 0 will reside in that address.

The ‘Address’ passed can be a reference,or a pointer that already points to some valid memory location,pointers such as NULL pointer or a pointer that hasn’t point to any location specifically will not work.It can be also a void pointer but it must also point to some location.In rare case the address can be a raw hexadecimal value signifying some unknown memory location.

int i , *ipt=&i , *ip , *iNul=nullptr;
void *vd=&i , *v ;

int *i=new(&i) int(0) ;   ///works fine
int *i1=new(ipt) int(9) ;  ///works fine
int *i2=new(ip) int(4) ;  ///error
int *i3=new(vd) int(34)  ///works fine
int *i4=new(v) int(1) ;  ///error
int *i5=new(i) int(3) ;  ///error
int *i6=new(iNul) int(6) ;  ///error
int *i7=new((void*)0x1ab23) ;  //works fine

When pointers ipt and vd are passed the code compiles but for the other pointers the message given by the Code::blocks(if you compile in CB) is “segmentation fault“(it means faulty uses of invalid memory location).The reason for this behavior is simple.The pointers ipt and vd point to the address of ‘i’ variable ,this means that they have the right to manipulate the memory of that variable.When these pointers(ipt and vd) are passed the placement new operator will use the memory where these pointers point to and make it as the home of the new value.As for the other pointers they do not hold the right to any specific memory location,so the placement new operator does not known where to make the new value reside and hence the call fails.In case where raw hexadecimal value casted to void type is passed-in the last line of the code- the compiler will deduce it as another normal memory address(since hexadecimal value is use for naming the memory) so the program compiles.But you better be careful with this one as some other program may be using the memory in that address and you can messed up big real time.


Deleting the storage used by the placement new operator.

The placement new operator uses the storage of another variable to put the new value or object in that storage.And we are aware that the storage-if new operator is not used to allocate the storage- of a variable/object is made during compile-time and so it is allocated in the Stack.The operator delete however can only delete the storage created in Heap,so when placement new is used we cannot call the delete operator to delete the storage.In this case we need not do anything about the storage,since it is created in stack the compiler knows when to delete it and it will handle deallocation of the memory for us automatically.





Class object and placement new operator.

Using placement new to construct a class object in a particular place will also behave in the same way as it did for the built-in type.In this case also the address passed must be a reference of another variable or object,if a pointer or a void pointer is passed they must point to certain valid memory location.The type of the data of which the address is passed if it is not void type,it must match with the type of the data member of the class.If the type does not match your program will compile but you may not get your expected output and in worst case scenario your program will break. Consider the program below.

class Test
{
private:
 string st;
 
public:
 Test(string s=””):st(s) { cout<< “Constructor \n” ; }

 string get( ) const { return st; }

 ~Test( ) { cout<< “Destructor \n” ; }
};

int main( )
{
string ss=”Dozo” ;
int i ;

// Test *t=new(&i) Test(“Drunken Master”) ;   //dangerous
Test *t=new(&ss) Test(“Drunken Master” ); //Peaceful

cout<< t->get( ) ;

t->Test::~Test() ; ///Explicit destructor call works fine

cin.get( ) ;
return 0 ;
}

The class Test has a data member of string type,if it’s object was made in the int type(&i) memory location there will be type conflict as the string data member of Test class is meant to reside in that address.This definitely will give some nasty result which we do not want.So it is always better that the type matched.

If you really has no option but to use the memory of other type then assign the address of that object/variable to void pointer first and passed that void pointer as an argument,this will prevent you from getting any error.

int i;
void *vd=&i ;

Test *t=new(vd) Test(“Drunken Master”) ;   ///Hurray it works and no error
cout<< t->get( );

Now the program works seamlessly and prints Drunken Master (I have alway wondered who is a better drunken master Jackie chan or Jet Lee? I think Jackie cause he can act better like a drunken guy and funny too).

Another thing to note in the program(the previous one) is the explicit destructor call.The object was created in string ‘ss’ variable whose storage is made in stack and we know for such storage the compiler will handle the freeing of memory then doesn’t the explicit destructor call seems superfluous? You must know,the destructor call does not delete the storage,only the delete operator does that,the real function of destructor is undoing what the constructor did.The constructor initialized the object or memory so it is the destructor function to uninitialized the memory.This implementation of destructor becomes useful when we require cleaning up of memory and making the memory available for another object,for instance consider the code below,

string st ;
Test *t=new(&st) Test(“Testing Destructor”) ;
cout<< t->get() ;
t->Test::~Test() ; ///calling the destructor explicitly

Test *tt=new(&st) Test(“New object creation”) ;   //New object created in the same location

t->Test::~Test() ;

After every explicit destructor call the memory can be used again for new object creation.Well it is better not to forget the destructor call if you want the memory cleaned up and keep it ready for another object to use it.The memory is completely destroyed only when the original owner of that memory,in our case ‘ss’ and ‘st’ goes out of scope.

string st;
{
string str;
Test *tst=new(&st) Test(“Drool”) ;
Test *tt=new(&str) Test(“Gomu gomu”) ;
}
Test *tOut=new(&str) Test(“Name”) ;   ///error,str out of scope
Test *tIn=new(&st) Test(“The world”);  //ok


What happen if the size of the memory passed is smaller than the size of the object.

In the above program the string size and the size of the object Test are the same so the object of Test can fit in perfectly in the string memory.Suppose if the size of Test object is larger than the size of the memory passed,then what happens? Here the compiler will allocate some extra space and the extra size equals to that of the remaining data members-total size excluding the first one- in the heap.And all I can say is such implementation is most probably a bug in your program.Consider the program below in which a variable string address is passed to the placement new operator but the actual size of the object is “sizeof(string) + sizeof(int)” ,which is also the size required.

class Test
{
private:
 string st ;

public:
 int i ;
 Test(string s=”” , int ii=0 ):st(s),i(ii)   { cout<< “Constructor \n” ; }

 ~Test() { cout<< “Destructor \n” ; }
};

int main( )
{
string ss=”new” ;

Test *t=new(&ss) Test( “old” , 90 ) ;

cout<< (int)&ss << endl
    << (int)t << endl /*or try this (int)t->s ,but make ‘s’ public */
    << (int)t->i << endl ;

cin.get( ) ;
return 0 ;
}

If you run the program in Visual Studio you will most probably get a message as “Stack around ‘ss’ is corrupted“; beware of this message! If you use Code::blocks there will be no error message but that doesn’t mean there is no error.The size of the storage-the size of ss- preserve for the object is not big enough to fit the whole object and so the compiler will allocate an extra storage to store the int data member of the object.But mind you this is not what you want because the compiler does it out of whim and you have not command the compiler to do so.The consequence is you may access the storage but you have no right over the destruction of the storage and also the compiler will not care what happen to that storage.Even if you try to destroy the storage using a delete operator as shown below.

int *iMem=&(t->i) ;

cout << *iMem ;///ok work fine

delete iMem ; ///undefined

The compiler will complain saying “Access violation in the location …“,the message is indeed true because you have not asked the compiler to create the (extra)storage and so how can the compiler give you the ownership of the storage,let alone accessing and destruction of the storage.The extra storage is just a mess created out of your ignorance and no one is responsible of that storage;perhaps you! All this can lead to just one conclusion,passing an object address to placement new operator whose size is smaller than the size of the object which is about to be created in that address is just plain wrong.If you want to use placement new without trying to create any trouble make sure that the size of the object passed is equal to the size of the object which will be created there.


Conclusion

In this post nothing much about placement delete operator is said.I have added the discussion of placement delete operator in another post.The placement delete operator is rather strange and does not function like the delete operator.Adding it’s discussion here will make this post cumbersome and so it’s discussion is done in another post.

Link: Use of palcement delete operator


Related Link

->Dynamically allocating memory in C++ with new and delete operators.
 
->Simplest way to overload placement new and placement delete operators.