gpt4 book ai didi

rust - 改变 MaybeUninit<[T; 是否合理? N]> 到 [MaybeUninit; N]?

转载 作者:行者123 更新时间:2023-11-29 07:46:48 25 4
gpt4 key购买 nike

下面的代码好听吗?

#![feature(maybe_uninit)]
use std::mem;
const N: usize = 2; // or another number
type T = String; // or any other type

fn main() {
unsafe {
// create an uninitialized array
let t: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninitialized();
// convert it to an array of uninitialized values
let mut t: [mem::MaybeUninit<T>; N] = mem::transmute(t);
// initialize the values
t[0].set("Hi".to_string());
t[1].set("there".to_string());
// use the values
println!("{} {}", t[0].get_ref(), t[1].get_ref());
// drop the values
mem::replace(&mut t[0], mem::MaybeUninit::uninitialized()).into_initialized();
mem::replace(&mut t[1], mem::MaybeUninit::uninitialized()).into_initialized();
}
}

我应该注意到 miri 运行它没有问题。

最佳答案

更正:下面的答案在一般情况下仍然成立,但在 MaybeUninit 的情况下有一些关于内存布局的方便的特殊情况使得这实际上是安全的:

首先,MaybeUninit 的文档有一个layout部分说明

MaybeUninit<T> is guaranteed to have the same size and alignment as T.

其次,语言引用说明了关于 array layouts 的内容:

Arrays are laid out so that the nth element of the array is offset from the start of the array by n * the size of the type bytes. An array of [T; n] has a size of size_of::<T>() * n and the same alignment of T.

这意味着 MaybeUninit<[T; n]> 的布局和[MaybeUninit<T>; n]的布局是一样的。


原答案:

据我所知,这是可能有效但无法保证的事情之一,并且可能受制于特定于编译器或特定于平台的行为。

MaybeUninit current source中定义如下:

#[allow(missing_debug_implementations)]
#[unstable(feature = "maybe_uninit", issue = "53491")]
pub union MaybeUninit<T> {
uninit: (),
value: ManuallyDrop<T>,
}

因为它没有标有 #[repr]属性(与例如 ManuallyDrop 相反),它是默认表示形式,其中引用 says this :

Nominal types without a repr attribute have the default representation. Informally, this representation is also called the rust representation.

There are no guarantees of data layout made by this representation.

为了转化自Wrapper<[T]>[Wrapper<T>] , Wrapper<T> 的内存布局一定是这样的与 T 的内存布局完全相同.许多包装器都是这种情况,例如前面提到的 ManuallyDrop , 这些通常会标有 #[repr(transparent)]属性。

但在这种情况下,这不是必然正确的。自 ()是零大小类型,编译器很可能会对 T 使用相同的内存布局和 MaybeUninit<T> (这就是它为你工作的原因),但也有可能 编译器决定使用一些其他内存布局(例如出于优化目的),在这种情况下转换将不再起作用。


作为一个具体的例子,编译器可能会为MaybeUninit<T>选择使用以下内存布局。 :

+---+---+...+---+
| T | b | where b is "is initialized" flag
+---+---+...+---+

根据上面的引述,编译器被允许这样做。在这种情况下,[MaybeUninit<T>]MaybeUninit<[T]>有不同的内存布局,因为MaybeUninit<[T]>有一个b对于整个阵列,而 [MaybeUninit<T>]有一个b对于每个 MaybeUninit<T>在数组中:

MaybeUninit<[T]>:
+---+...+---+---+...+---+...+---+...+---+---+
| T[0] | T[1] | … | T[n-1] | b |
+---+...+---+---+...+---+...+---+...+---+---+
Total size: n * size_of::<T>() + 1

[MaybeUninit<T>]
+---+...+---+----+---+...+---+----+...+---+...+---+------+
| T[0] |b[0]| T[1] |b[1]| … | T[n-1] |b[n-1]|
+---+...+---+----+---+...+---+----+...+---+...+---+------+
Total size: (n + 1) * size_of::<T>()

关于rust - 改变 MaybeUninit<[T; 是否合理? N]> 到 [MaybeUninit<T>; N]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55313460/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com