Skip to content

Tracking issue for uninitialized constructors for Box, Rc, Arc #63291

Closed

Description

Assigning MaybeUninit::<Foo>::uninit() to a local variable is usually free, even when size_of::<Foo>() is large. However, passing it for example to Arc::new causes at least one copy (from the stack to the newly allocated heap memory) even though there is no meaningful data. It is theoretically possible that a Sufficiently Advanced Compiler could optimize this copy away, but this is reportedly unlikely to happen soon in LLVM.

This issue tracks constructors for containers (Box, Rc, Arc) of MaybeUninit<T> or [MaybeUninit<T>] that do not initialized the data, and unsafe conversions to the known-initialized types (without MaybeUninit). The constructors are guaranteed not to make unnecessary copies.

PR #62451 adds:

impl<T> Box<T> { pub fn new_uninit() -> Box<MaybeUninit<T>> {} }
impl<T> Box<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Box<T> {} }
impl<T> Box<[T]> { pub fn new_uninit_slice(len: usize) -> Box<[MaybeUninit<T>]> {} }
impl<T> Box<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Box<[T]> {} }

impl<T> Rc<T> { pub fn new_uninit() -> Rc<MaybeUninit<T>> {} }
impl<T> Rc<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Rc<T> {} }
impl<T> Rc<[T]> { pub fn new_uninit_slice(len: usize) -> Rc<[MaybeUninit<T>]> {} }
impl<T> Rc<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Rc<[T]> {} }

impl<T> Arc<T> { pub fn new_uninit() -> Arc<MaybeUninit<T>> {} }
impl<T> Arc<MaybeUninit<T>> { pub unsafe fn assume_init(self) -> Arc<T> {} }
impl<T> Arc<[T]> { pub fn new_uninit_slice(len: usize) -> Arc<[MaybeUninit<T>]> {} }
impl<T> Arc<[MaybeUninit<T>]> { pub unsafe fn assume_init(self) -> Arc<[T]> {} }

PR #66128 adds:

impl<T> Box<T> { pub fn new_zeroed() -> Box<MaybeUninit<T>> {} }
impl<T> Arc<T> { pub fn new_zeroed() -> Arc<MaybeUninit<T>> {} }
impl<T> Rc<T> { pub fn new_zeroed() -> Rc<MaybeUninit<T>> {} }

Unresolved question:

  • The constructor that returns for example Box<MaybeUninit<T>> might “belong” more as an associated function of that same type, rather than Box<T>. (And similarly for other constructors.) However this would make a call like Box::<u32>::new_uninit() becomes Box::<MaybeUnint<u32>>::new_uninit() which feels unnecessarily verbose. I suspect that this turbofish will be needed in a lot of cases to appease type inference.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-raw-pointersArea: raw pointers, MaybeUninit, NonNullB-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: A tracking issue for an RFC or an unstable feature.Libs-TrackedLibs issues that are tracked on the team's project board.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.requires-nightlyThis issue requires a nightly compiler in some way.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions