简体   繁体   中英

Can I call placement-new and the destructor through references?

Can I pass around references to uninitialized memory, take the address, and then call placement-new or call the destructor on the obtained memory-location. In other words, is the following program legal C++ or does it have undefined-behavior:

#include <string>
#include <iostream>

void ctor (std::string &s)
{
  new (&s) std::string ("Hello, world!");
}

void dtor (std::string &s)
{
  (&s)->std::string::~string ();
}

int main ()
{
  std::string * memory = static_cast<std::string *> (
    operator new (sizeof (std::string) * 10));

  ctor (memory [0]);

  std::cout << memory [0] << '\n';

  dtor (memory [0]);

  operator delete (memory);
}

It works, of course, and I tried gcc's undefined behavior sanitizer, which didn't produce any errors. But can anyone confirm/refute based on the standard.

The above code double-constructs a string at [0] , which is a potential resource leak, and double destroys it, which is undefined behaviour.

new string[10] constructs objects in array. delete[] destroys the objects. You create a new object on top of another, then destroy it, then destroy it again when you delete[] .

Nothing else looks wrong; I mean it uses raw allocation which is bad practice in general, and the code is exception unsafe, etc.

dtor (memory [0]);

delete [] memory;

Is definitely undefined behavior.

The lifetime of the object that was constructed in the line

std::string * memory = new std::string [10];

ended when you use the placement new operator.

Hence,

delete [] memory;

is undefined behavior.

Update

The updated lines of code

dtor (memory [0]);

operator delete (reinterpret_cast<void *> (memory));

is well behaved.

The destructor of the object allocated with the placement new operator is called only once.

The memory allocated by the operator new call gets deallocated by the operator delete call.

After your edit, there does not seem to be undefined behavior anymore.

However, there's still danger in your code :
Your memory variable has the type of a pointer to a constructed string, even though there is no string behind that pointer after initialization of the pointer. And the pointer is not nullptr either. That's dangerous. You are asserting to the compiler that something is a correctly constructed object, which isn't. As such, your compiler won't catch you in the act of using the unconstructed objects erroneously.

I would strongly recommend keeping track of the uninitialized memory with char* variables, and only use class typed pointers for objects that are already correctly constructed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM