Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it okay to give a stack object address to placement new?

Ignoring usefulness of such practice. (Though real-life examples are welcome, of course.)

For example, the following program outputs the correct value for a:

#include <iostream>

using namespace std;

int main()
{
  int a = 11111;
  int i = 30;

  int* pi = new (&i) int();

  cout << a << " " << endl;
}

But isn't new-allocation supposed to create some bookkeeping information adjacent to i (for correct subsequent deallocation), which in this case is supposed to corrupt the stack around i?

like image 659
Lmn Avatar asked Jul 15 '15 14:07

Lmn


2 Answers

Yes, it's perfectly OK to perform placement-new with a pointer to an object on the stack. It will just use that specific pointer to construct the object in. Placement-new isn't actually allocating any memory - you have already provided that part. It only does construction. The subsequent deletion won't actually be delete - there is no placement delete - since all you need to do is call the object's destructor. The actual memory is managed by something else - in this case your stack object.

For example, given this simple type:

struct A {
    A(int i) 
    : i(i)
    {
        std::cout << "make an A\n";
    }

    ~A() {
        std::cout << "delete an A\n";
    }

    int i;
};

The following is completely reasonable, well-behaved code:

char buf[] = {'x', 'x', 'x', 'x', 0};
std::cout << buf << std::endl;  // xxxx
auto a = new (buf) A{'a'};      // make an A
std::cout << a->i << std::endl; // 97
a->~A();                        // delete an A

The only case where this would be invalid would be if your placement-new-ed object outlasts the memory you new-ed it on - for the same reason that returning a dangling pointer is always bad:

A* getAnA(int i) {
    char buf[4];
    return new (buf) A(5); // oops
}
like image 102
Barry Avatar answered Oct 29 '22 16:10

Barry


Placement new constructs the element in place and does not allocate memory.

The "bookkeeping information" in this case is the returned pointer which ought to be used to destroy the placed object.

There is no delete associated with the placement since placement is a construction. Thus, the required "clean up" operation for placement new is destruction.

The "usual steps" are

  1. 'Allocate' memory
  2. Construct element(s) in place
  3. Do stuff
  4. Destroy element(s) (reverse of 2)
  5. 'Deallocate' memory (reverse of 1)

(Where memory can be stack memory which is neither required to be explicitly allocated nor deallocated but comes and goes with a stack array or object.)

Note: If "placing" an object into memory of the same type on the stack one should keep in mind that there's automatic destruction at the end of the object's lifetime.

{ 
  X a;
  a.~X(); // destroy a
  X * b = new (&a) X(); // Place new X
  b->~X(); // destroy b
} // double destruction
like image 22
Pixelchemist Avatar answered Oct 29 '22 17:10

Pixelchemist