Obviously I'm missing something here, so I'll post in the beginner's forum.
Query:
Why would I ever use placement new?
Obviously I'm missing something here, so I'll post in the beginner's forum.
Query:
Why would I ever use placement new?
//simple stack allocator, deconstructed:
char stack[1024];
int size = 0;
struct Obj { Obj() {...} ~Obj() {...} };
//manually construct 3 objects inside the pre-allocated memory
Obj* foo = new(&stack[size]) Obj; size += sizeof(Obj);
Obj* bar = new(&stack[size]) Obj; size += sizeof(Obj);
Obj* baz = new(&stack[size]) Obj; size += sizeof(Obj);
//manually destruct them when done
foo->~Obj();
bar->~Obj();
baz->~Obj();
size = 0;
This is especially important if the 'Obj' class has any virtual methods. In that case, the constructor doesn't just run your code to initialize the members, it also initializes the vtable pointer, so that your virtual methods actually work . 22 Racing Series .
So if the ctor is called manually on a derived class it doesn't set up the vtable?
Edit:
Er... This thing isn't letting me call the ctor manually. Is that new or am I remembering incorrectly?
Placement new is what you would write to call the constructor manually for some memory you provide, if you would write only a constructor call it would mean something else like making a temporary or casting a value.
Btw. if one doesnt need normal new and placement new at same time for a single class one can also overwrite operator new and delete for that class and then new and delete it normally, without needing the weirdness of placement new and direct destructor calls.
As an example of a usage of placement new:
I create a placement new pointer to shared memory (on Linux systems). Shared memory, depending on implementation, can actually be placed directly in /dev/shm as a RAM disk. If you need two complete processes to share information it's one way of doing things.
IIRC I've seen implementations that use placement new on things like internal timers. As Hodgman points out, this is almost never a concern for high level programmers.
Edit: Clarifying the implementation of the RAM disk on Linux.
It can also be used (with care) to initialize memory-mapped I/O devices if you want a direct object representation of the memory that controls it. Sometimes its better to have an object representation which is a proxy for the object, but sometimes not. You can use placement new with careful construction in the latter case. I say careful because you have to make sure your class's data members line up with the in-memory registers, and you also have to initialize some of those registers in the manner and order that the hardware requires -- but its a neat parlor trick when the opportunity arises.
throw table_exception("(? ???)? ? ???");
It can also be used (with care) to initialize memory-mapped I/O devices if you want a direct object representation of the memory that controls it. Sometimes its better to have an object representation which is a proxy for the object, but sometimes not. You can use placement new with careful construction in the latter case. I say careful because you have to make sure your class's data members line up with the in-memory registers, and you also have to initialize some of those registers in the manner and order that the hardware requires -- but its a neat parlor trick when the opportunity arises.
Aye. I was wondering about that earlier. I've never really worked with such a device, but I was thinking that maybe that was the reasoning behind it.
It can work, but I don't think I'd go as far as saying it was a critical part of the reasoning behind it. Enabling custom allocations like others have described is a damn fine reason all on its own. And like I said, you first have to ensure your data aligns to the registers, and then have to possibly initialize those registers in the correct order, and sometimes going back to write new values to them mid-way-through, in order to actually bring up the hardware device correctly. In C++ order of initialization by default is related to the order in which member variables are declared, so C++ is somewhat at odds with the needs of some hardware. You can work around it, of course, by having an init member-function but that negates some of the utility of classes. Its sometimes more practical to just write a macro that dereferences the right address and casts to a class representing the type, with a free-standing init function.
But definitely memory-mapped IO was on their minds in general, that's actually what bit-fields are for -- they're not meant so that you can pack your data (if they were, they're a half-baked solution for that).
throw table_exception("(? ???)? ? ???");