views:

304

answers:

5

What is the second line? (Seen while answering another question.)

int * x = new int [1] ;
int * y = new (x) int;

After the second line x and y have the same value (point to a same place). What's the difference between y = x and the second line? Is it like a constructor or something?

+4  A: 

This is called placement new. It allows you to construct an object in memory already allocated.

This earlier thread discusses where and how it is useful for.

Péter Török
I don't completely get it! when we new something again it's pointer is changed! but how does this work without changing the pointer! see the output of VCEXPRESS8: x before the second line 0x005c4e58 x after the second line 0x005c4e58 are the same!
Green Code
It tells the compiler "do the usual constructor, but instead of creating more memory, use the memory at `x`." So it doesn't modify `x`, but overwrites the `int` you created in the first line.
Jonathan Grynspan
@Green, there is no new memory allocated with placement new, this is why `y` in your example points to the same memory address as `x`. Think of it as simply omitting the memory allocation step, and executing the appropriate constructor call immediately, using the supplied memory block.
Péter Török
So, if I understand it correctly, what you get in the end is 2 pointers to a structure in the same memory block? Why use X and Y then? Why don't just stick with X?
EKI
@EKI, the example above uses `int` type, where there is not much diffeence. However, with nonprimitive types, there can be a big difference. You may e.g. allocate an array of `char`s of suitable size, then initialize a `YourFavouriteType` object to it with placement new. Then you have a `char*` and a `YourFavouriteType*` pointing to physically the same memory, but "seeing" possibly very different things.
Péter Török
@EKI, what's more, you can initialize several distinct objects to consecutive addresses within the same big memory buffer - this is basically what a custom allocator may do.
Péter Török
+11  A: 

It's placement new. It constructs a new int in the memory pointed to by x.

If you try:

int * x = new int [1];
*x = 5;
std::cout << *x << std::endl;
int * y = new (x) int;
*y = 7;
std::cout << *x << std::endl;

the output will be:

5
7
Oli Charlesworth
but x does not change where it already pointed!
Green Code
Nothing happens to `x`. But something may happen to `*x`. Try the following: `int * x = new int [1] ; *x = 5; std::cout << *x << std::endl; int * y = new (x) int; *y = 7; std::cout << *x << std::endl;`
Oli Charlesworth
@Green Code: It's correct. Placement new just performs initialization. It's like calling the constructor for that type on the given allocated memory.
Matteo Italia
what is the diffrence between y=x and y= new (x) int? what you did could also be done by "y=x; *y=7;"
Green Code
@Green Code: For primitive types, yes, there's essentially no difference. For class types, there's a big difference, as the constructor will get called again.
Oli Charlesworth
That's what i was searching for ;), also you voted one of my question down where i meant parent in intritance or base class. I edited so you can undo vote down :D. tanx;
Green Code
@Geen Code: Placement new is not usually used like this. See below.
Martin York
Remember `new(x) int` != `new(x) int()`!
Roger Pate
@Martin: What is this "below"? :)
Roger Pate
+3  A: 

The second new is a "placement new". It performs initialization (i.e. call any necessary constructors) without doing any allocation. It is useful when you need to create a custom memory allocation scheme.

Ferruccio
+2  A: 
int * y = new (x) int; 

This is as per placement new syntax.

EDIT: Along with custom allocation, placement new also helps to re-initialze an object state like below.

class Test
{
    int startVal;
public:
    Test()
    {
        startVal = 1;
    }
    void setVal(int val) { startVal = val; }
};
int main()
{
    Test *p = new Test;  //Creates new object and initializes it with
                          //a call to constructor.
    p->setVal(10);  //Change object content.
    new(p) Test; //Reset object:
    //object pointed by p will be re-initialzed here by making
    //a call to constructor. startVal will be back to 1
}

As described in comments above, object state resetting also can be achieved using placement new. placement new doesn't allocate memory, it constructs object at the specified address in the paranthesis.

bjskishore123
That is not a good idea. What happens if Test contained a pointer member. Because you did not call the destructor on the original object you will probably leak memory. If you are going to use placement new to reset a value (which is usually a bad idea) you must call the destructor on the object first (you can manually call the destructor via the pointer).
Martin York
@Martin: Good point. But I saw re-setting being used in our widely used commercial code. They do not have any pointer inside the class. Not sure whether it is bad practice. Anyways, thank you.
bjskishore123
+2  A: 

This is placement new.

Though you don;t usually use it with integer types.
It is usually used to build a buffer where you then build other types into.

// Allocate a buffer with enough room for two T objects.
char* buffer   = new char[sizeof(T) * 2];

// Allocate a T in slot zero
T* t1 = new (buffer + 0 * sizeof(T)) T("Zero");

// Allocate a T in slot one
T* t2 = new (buffer + 1 * sizeof(T)) T("One");

Thats the basics.
But remember that the objects allocated with placement new can not be deleted with the delete statement. This is because delete tries to reclaim memory allocated by new (as well as call the destructor). So to use these objects correctly you must manually call there destructor.

t1->~T();
t2->~T();

Don't forget to delete the original buffer.

delete [] buffer;

A few other caveats:
People often see that buffer could be implemented on the stack and thus be automatically freed

char buffer[sizeof(T) * 2];

Unfortunately this may be technically OK (It compiles). But it is not guaranteed to work as the memory of buffer may not be aligned correctly for a T to be placed inside. So you must allocate the buffer dynamically (by using new it gurantees that the memory is aligned correctly for any object of the size allocated (thus by extension it is also aligned for any size smaller then the size allocated). The easy way to get around this problem is to use a std::vector

std::vector<char>    buffer(sizeof(T) * 2);
T* t1 = new (&buffer[0] + 0 * sizeof(T)) T("Zero");
T* t2 = new (&buffer[0] + 1 * sizeof(T)) T("One");

Another use of placement new is to reset an object.
I have seen this done but I prefer to use the more standard assignment operator:

T   obj1("Plop");
obj1  = T("Another Plop");

// Can be done like this:
T   obj1("Plop");
obj1.~T();
new (&obj1) T("Another Plop");   // Seems excessive to me. But can be us-full
                                 // in some extreme situations.

Remember if you use the reset method you must destroy the old object first (or the object may not behave correctly).

Martin York