试图理解Box::pin()和Pin::new_unchecked()之间的区别。假设以下代码:
use std::pin::Pin;
use std::marker::PhantomPinned;
struct Foo {
x: i32,
_pin: PhantomPinned,
}
fn bar() {
let fives = Foo {
x: 5,
_pin: PhantomPinned,
};
let mut boxed = Box::pin(fives);
unsafe {
let mut_ref: Pin<&mut Foo> = Pin::as_mut(&mut boxed);
Pin::get_unchecked_mut(mut_ref).x = 55;
}
println!("fives: {}", boxed.x);
// fives.x = 555; //Won't compile Box::pin() consumed fives.
let mut twos = Foo {
x: 2,
_pin: PhantomPinned,
};
let mut ptr = unsafe{ Pin::new_unchecked(&mut twos) };
unsafe {
let mut_ref: Pin<&mut Foo> = Pin::as_mut(&mut ptr);
Pin::get_unchecked_mut(mut_ref).x = 22;
}
println!("twos: {}", twos.x);
twos.x = 222;
println!("twos: {}", twos.x);
}
fn main() {
bar();
}我的理解是:
boxed和twos,因此当它们超出范围时,会调用drop()。drop()不需要为Foo手动实现。fives存在于堆中,twos存在于堆栈中。这是正确的吗?什么时候Box::pin()合适,什么时候Pin::new_unchecked()合适?什么时候需要为一个drop()结构实现!Unpin?
发布于 2020-11-27 22:32:22
Box::pin始终是安全的使用。盒式值已经属于该框,并将其移动到一个Pin中,以保证当时没有其他对其的引用,因为借入检查器不会允许移动发生。只有在实现由类型检查器强制执行的Unpin时,内容才能解除锁定。
Pin::new_unchecked并不总是安全的使用。它采用任意指针类型,而不仅仅是一个框,并且可能存在该指针的其他副本。因为指针可以是任何东西,所以编译器不能保证它所指向的数据不会被其他代码移动,除非先解除锁定。当您使用Pin::new_unchecked时,这取决于您是否强制执行生成Pin的用户所期望的所有假设。如果不这样做,则可能触发未定义的行为。
碰巧,Pin::new_unchecked总是可以安全地与不可变的&-references和Box一起使用。但是,与可变的&mut-references Rc、Arc或原始指针一起使用是不安全的,除非您独立地确保所有的引脚保证都被强制执行。详细介绍了Pin::new_unchecked在其文件中的安全性。
文档提供了Pin::new_unchecked如何使用&mut引用导致UB的示例:
use std::mem;
use std::pin::Pin;
fn move_pinned_ref<T>(mut a: T, mut b: T) {
unsafe {
let p: Pin<&mut T> = Pin::new_unchecked(&mut a);
// This should mean the pointee `a` can never move again.
}
mem::swap(&mut a, &mut b);
// The address of `a` changed to `b`'s stack slot, so `a` got moved even
// though we have previously pinned it! We have violated the pinning API contract.
}https://stackoverflow.com/questions/65043756
复制相似问题