Skip to content

Consider adding Box::uninitialized function #46406

Closed
@malbarbo

Description

@malbarbo

The reasons for such a function are the same as for std::mem::uninitialized. I saw somewhere a discussion about deprecating std::mem::uninitialized, but I cannot remember where. If this is the case, how to avoid the cost of initializing a huge structure in the heap that will be initialized again in a ffi function call (without writing c code)?

Also, it would be great to have Box::uninitialized_from_value that take a reference to a value and return a uninitialized boxed value that could store a copy of the original value. This function is useful to implement clone for structures containing unsized types. For example:

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct A<T: ?Sized> {
    a: u8,
    b: T,
}

#[derive(Debug, Eq, PartialEq)]
struct X {
    inner: Box<A<[u32]>>,
}

impl Clone for X {
    fn clone(&self) -> X {
        unsafe {
            let mut inner = Box::uninitialized_from_value(&*self.inner);
            inner.a = self.inner.a;
            inner.b.copy_from_slice(&self.inner.b);            
            X { inner: inner }
        }
    }
}

fn main() {
    let x = X {
        inner: Box::new(A {
            a: 10,
            b: [1, 2, 3, 4, 5],
        }),
    };
    let y = x.clone();
    assert_eq!(x, y);
}

If instead of [u32], we had a generic [T] we would had to be very careful in the clone implementation, but it would be possible do to so using the stable compiler. The issue is that without Box::uninitialized_from_value I think it would be impossible to create an efficient implementation for X::clone (generic over the array item) without using std:heap and the nightly compiler.

Here is a possible implementation (I'm not sure it is correct):

#![feature(allocator_api)]

use std::ptr;
use std::heap::{Alloc, Heap, Layout};
use std::mem;

trait Uninitialized<T: ?Sized> {
    unsafe fn uninitialized_from_value(value: &T) -> Self;
}

impl<T: ?Sized> Uninitialized<T> for Box<T> {
    unsafe fn uninitialized_from_value(value: &T) -> Self {
        let layout = Layout::for_value(value);
        let ptr = Heap.alloc(layout).unwrap_or_else(|e| Heap.oom(e));
        // Initialize b with value so b has the right DST extra field if T is ?Sized
        let mut b: Box<T> = mem::transmute(value);
        // Change the pointer to the newly allocated memory
        ptr::write(&mut b as *mut _ as *mut *mut u8, ptr);
        b
    }
}

This code is based on Rc::allocate_for_ptr (which is similar to Arc::allocate_for_ptr). Box::uninitialized_from_value could be used in Rc::allocate_for_ptr, which indicates that there are uses cases for such a function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions