简体   繁体   中英

Placement-new vs new-expression

Again with placement new I've found an example on this forum like this:

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation
  • But I think here buf is a pointer to an allocated and Constructed dynamic array of default-init characters. So the characters in the array are default initialized and have an indeterminate values.

  • I guess using the placement new in the second line will constructs objects on the previously constructed array of objects.

  • Why the user didn't call operator new on the array allocation rather than using new expression?:

     char *buf = static_cast<char*>(operator new[](sizeof(string)));
  • After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.

  • Are my guesses correct?

Here is the link to the original answer:

What uses are there for "placement new"?

Why the user didn't call operator new on the array allocation rather than using new expression?:

We cannot answer that question because we aren't that user. You should ask that from the user - though given that the example was written in 1998 it might not be easy to contact them. My guess: They didn't know that non-placement operator new exists or they didn't know what it is used for. Reusing the memory of an array of char is an intuitive choice in such case.

Note that the example of creating a singular dynamic std::string object makes little sense in the first place (I'm assuming that's what string in the example is).

I have a similar question to you: Why are you using operator new[] in your suggestion and not operator new ? Even more importantly, why not use an allocator?

Are my guesses correct?

  1. Correct.
  2. Correct.
  3. This is a question and not a guess. I covered it above.
  4. It would fail. But that's irrelevant since char is default constructible.

char is an object type that is both fundamental and trivial. Creating one doesn't, in practice, touch memory, and making an array of them does not either.

char* foo = new char[10];

and

char *foo  = static_cast<char*>(operator new[](10));

end up doing exactly the same thing in machine code, except the second one is a lot more verbose.

There are some subtle differences in the abstract machine; in one a bunch of chars are created, in the other the other they are not on that line. Coming up with a case where that matters is going to require a fair bit of language lawyering effort (I am thinking disposal may be different, and some access might be different, especially in standard versions before c++ fixed the malloc problem).

After all I think if buff is a pointer to a dynamic array of non-default-constructible objects then the code will fail to compile using the new expression rather than using the operator new function.

Sure, but the cast would be code smell, and the point of buf is to be storage for the later placement new. I guess it already is,

void *foo  = operator new[](10);

is less bonkers.

Just because you can static cast does not mean you should.

operator new[](sizeof(string)) that's something odd, its incorrect syntax for creating an object. In best case scenario it creates an object in memory implicitly (if operator new implemented as std::malloc call and object is a POD type), without initializing or constructing one. All you can do in that case is to static_cast<char*>(new string); The offered line just would create a string object in dynamic storage and then make it anonymous by replacing type of pointer by char* .

Thing is, for placement new buf is not necessary to point to dynamic memory. It can be a static buffer.It can be a pointer to memory location within a rather large storage used to store multiple objects, a memory pool. New object would constructed at given location.

Note that in case of placement new std::string 's data storage is still behaves as it usually does - it allocates character data in dynamic memory. To use some memory pool, programmer should provide appropriate allocator and that's one of purposes for placement new operator.

No, buf isn't an array of objects. It's an array of characters, so basically an array of bytes. And while it was allocated with an array new, its basically being used as a byte pointer.

The use of placement new is if you want to allocate an object at an exact location, but you want to do so following all the rules of C++ object allocation- so constructors called and vtables set up. The usual use case for this is if you're doing your own custom memory allocation and reusing existing memory addresses. Firmware may use this to reuse memory as a pool. Or an RTOS may use it so that it doesn't exceed memory restrictions for a task.

This is actually a poor example of how its used because of that. You'd never new an array then placement new into it. You'd have a pointer to a block of allocated memory lying around, and you'd use placement new into that.

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