wg icon indicating copy to clipboard operation
wg copied to clipboard

Placement New

Open aclysma opened this issue 5 years ago • 4 comments

It's common in game development to want fine-grained control of where values are allocated. This would commonly be used in object pools/ECS systems.

Support for this used to exist, but was removed. The reasons are summarized here: https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911

Possibly oversimplified, the conventional/expected new() syntax does not accept a &self, constructing explicitly always goes to the stack (i.e. TheType { a: 1, b: 2} ), and neither of these allows for the allocation to fail. So it's unclear how this would be implemented in a way that is reliable.

I do not see any recent activity working on this.

It is possible in some cases that the optimizer would optimize away the stack temporary being copied to a heap address, but:

  • It would never occur in debug
  • It's quite a difficult optimization, in many cases requiring LTO. It couldn't be relied upon.

Some workarounds:

  • MaybeUninit and unsafe code.
  • Use unconventional ways of construction i.e. init(&mut self)
  • Carefully structuring code to make it highly likely the optimizations will be taken (i.e. container.push_with(|| TheType {a: 1, b: 1})
  • Crates can help with this. A couple different approaches:
    • https://crates.io/crates/copyless
    • https://crates.io/crates/boxext
    • https://crates.io/crates/default-boxed

aclysma avatar Sep 02 '19 05:09 aclysma

There is a bit of support that landed in the compiler: https://github.com/rust-lang/rust/pull/62451

kvark avatar Sep 04 '19 19:09 kvark

That change looks like a targeted approach to avoid a stack-to-heap copy into a newly constructed Box/Rc/Arc, rather than a general solution to put a value into a specific place in memory. It also requires unsafe code to use for every construction. (Understandable, even if not ideal, given that this is a low-level, uncommon thing to do.)

One option we've discussed in the bi-weekly meeting was to have some sort of function that takes a pointer or MaybeUninit<T> as an input and returns a T as output. It may be possible for the compiler to verify that all fields have been initialized to something. This would move one class of errors to being caught at compile time.

The common case that generally has me reaching for placement new is implementing an object pool. So perhaps helpful guidance here for myself and others wanting placement new would be to simply use an existing object pool crate or implement it yourself with unsafe code.

aclysma avatar Oct 02 '19 04:10 aclysma

The common case that generally has me reaching for placement new is implementing an object pool.

Sounds like it would be covered by VecHelper to some extent.

kvark avatar Oct 02 '19 18:10 kvark

Currently, there is a discussion on Zulip about placement new.

Wodann avatar Jan 24 '20 10:01 Wodann