Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Placement new is kind of niche but it's not as rare as you might think, especially if you consider cases where you're using it through some other abstraction. For example, in C++ std::shared_ptr is implemented as the the object you're pointing to, plus another data structure called a control block that contains the reference count for the pointed-to data. The control block has to be heap allocated. If you're allocating a shared object, you could allocate the object being pointed to, and then also allocate the control block... but that requires two allocations. That's why the standard library has std::make_shared, which does a single allocation for both the object being pointed to as well as the control block (there's also a secondary benefit which is that the control block is adjacent in memory to the data it points to, which improves memory locality and caching). To implement std::make_shared you need to use placement new, as you're doing one allocation and two initializations.

I write C++ as my day job and while I wouldn't say I have to write placement new code often (I don't think I've used it once in the past year), it's definitely an essential tool for writing certain abstractions.



For sure. That's interesting, thank you for sharing. In Rust an Arc<T>, the equivalent to shared_ptr, would also require a single contiguous allocation, because it's size is the size of T plus the size of the Arc's internal state. But I must be missing something because C++ has had templates since more then a decade before Rust 1.0 released. I suspect the difference is in how object lifetimes are handled & Rust's lack of a language-level concept of a constructor or a new keyword.

Skimming the source code for Arc<T>, it looks like T will likely be on the stack & copied to the heap, adding a copy C++ is probably able to avoid with it's strategy, but I'm not sure if the compiler is able to optimize that out or not.


> I suspect the difference is in how object lifetimes are handled & Rust's lack of a language-level concept of a constructor or a new keyword.

Object lifetimes certainly play a role. The data structure used by the shared pointer can be kept alive by a weak pointer, but you want to call the destructor of the embedded object when no more shared pointers point to it. If you just used a templated member the auto generated cleanup code would try to call the destructor when the data structure itself is disposed. That is too late if weak_ptrs where involved and you can't call the destructor manually before that without causing loads of FUN as the automated cleanup will try to destroy the object again later. With placement new the member object can be created and destroyed as needed without the language imposing any assumptions on the objects lifetime.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: