Rust 中的堆栈分配与堆分配到底是如何工作的?

Dou*_*oug 1 rust

因此,我理解其工作原理的简单答案是,本地内容发生在堆栈中,而盒子内容发生在堆中。

然而,当你有更复杂的行为时会发生什么?

具体来说,让我们讨论一下在 FFI 中保存一段不确定时间、然后必须稍后从 *mut c_void 中恢复的数据。

如果您“忘记”了一个指针,使用 std::mem::forget 或 std::mem::transmute() 指向 *const 指针的指针,结果的持久性如何?

如果(例如)这是在函数内部完成的,然后函数返回,堆栈是否会被清除并且内存会变得无效?

一般而言,堆分配的“Box”指针在被销毁之前是否有效(例如使用 read())?

我在 IRC 上被告知,这通常是正确的方法:

unsafe fn fp(v:Box<Foo>) -> *const c_void {
  return transmute(foo);
}
Run Code Online (Sandbox Code Playgroud)

然而,看看 libcore::raw::Box,Box 与 *const T 完全不同;真的可以吗?

huo*_*uon 5

如果您“忘记”了一个指针,使用 std::mem::forget 或 std::mem::transmute() 指向 *const 指针的指针,结果的持久性如何?

Box如果您通过函数使用 transmute进行转换fp,只要您愿意,指针将保持有效,因为transmute正在消耗该值,因此释放内存的析构函数不会运行。(至少,在您将其转换回让Box<...>析构函数运行并释放内存之前,它是有效的。)

forget没有返回值,它只是丢弃该值而不运行析构函数。

但请注意,转换为*const c_void需要额外小心,例如Foo 内部Box<Foo>包含线程本地数据或引用,因此可能无法在线程之间传递有效,或永远存在。(意味着指针本身永远存在/可以随心所欲地使用,但它指向的数据可能不会。)

如果您开始转换&指针,则需要非常小心生命周期,不要让它们逃离它们指向的数据范围(例如,您不能从函数返回指向局部变量的指针)。

如果(例如)这是在函数内部完成的,然后函数返回,堆栈是否会被清除并且内存会变得无效?

堆栈不会被“清除”(即它没有显式清零),但使用任何指向不再存在的堆栈帧的指针是无效的。

一般而言,堆分配的“Box”指针在被销毁之前是否有效(例如使用 read())?

您需要更具体,不能直接ptr::read调用 a ,并且调用a当然不会做任何有用的事情。Boxptr::read*const c_void

然而,看看 libcore::raw::Box,Box 与 *const T 完全不同;真的可以吗?

raw::Box根本不是正常的表现Box。是旧(现在)类型raw::Box的表示。实际上是a 的包装@GcBox<T>*mut T