rust 就地初始化Rc并跳过内存

dz6r00yl  于 2023-03-18  发布在  其他
关注(0)|答案(3)|浏览(271)
use std::rc::Rc;

pub fn test() -> Rc<[usize; 1024]> {
    Rc::new([42; 1024])
}

如果我compile这段代码,我可以看到Rust在堆栈上用42填充一个数组,然后在堆上分配并调用memcpy将值从堆栈复制到新分配的区域,这是很浪费的。
让Rust直接在堆上初始化数组,而不是先在堆栈上初始化它,以避免memcpy,最简单的方法是什么?

aiazj4mn

aiazj4mn1#

据我所知,目前没有办法直接分配Rc<[T; N]>而不从stable的堆栈中复制数据,每晚可以手动初始化Rc,如下所示:

#![feature(new_uninit)]
use std::rc::Rc;
use std::mem::MaybeUninit;

pub fn test<const N: usize>() -> Rc<[usize; N]> {
    let mut r: Rc<[MaybeUninit<usize>]> = Rc::new_uninit_slice(N);
    for f in Rc::get_mut(&mut r).unwrap().iter_mut() {
        f.write(42);
    }
    // SAFETY:
    // * all elements are initialized
    // * the metadata can safely be dropped since it's encoded in the returned type
    // * layout of `MaybeUninit<T>` is the same as `T`
    unsafe { Rc::from_raw(Rc::into_raw(r).cast()) }
}
apeeds0o

apeeds0o2#

不需要每晚伸手,这可以在马厩里完成(注意:仅在启用优化时不复制):

use std::mem::MaybeUninit;
use std::rc::Rc;

pub fn test() -> Rc<[usize; 1024]> {
    let mut rc = Rc::new(MaybeUninit::<[usize; 1024]>::uninit());
    // SAFETY: `MaybeUninit<[T; N]>` and `[MaybeUninit<T>; N]` have the same layout,
    // and both can stay uninitialized.
    let data = unsafe {
        &mut *(Rc::get_mut(&mut rc).unwrap() as *mut MaybeUninit<[usize; 1024]>
            as *mut [MaybeUninit<usize>; 1024])
    };
    for item in data {
        item.write(42);
    }
    // SAFETY: `MaybeUninit<T>` and `T` have the same layout, and we initialized it above.
    unsafe { Rc::from_raw(Rc::into_raw(rc).cast::<[usize; 1024]>()) }
}
xytpbqjk

xytpbqjk3#

this answer的基础上构建,首先可以创建一个Box<[usize; 1024]>,然后将其转换为Rc,因为Rc<T>实现了From<Box<T>>

use std::rc::Rc;

pub fn test() -> Rc<[usize; 1024]> {
    let boxed_slice = vec![42; 1024].into_boxed_slice();
    let ptr = Box::into_raw(boxed_slice) as *mut [usize; 1024];
    // SAFETY: the data of a `[T; N]` has the same layout as that of
    // a `[T]` and we allocated a slice of the right size.
    let b = unsafe { Box::from_raw(ptr) };
    b.into()
}

Godbolt

相关问题