如何在稳定的 Rust 中在不占用堆栈空间的情况下在堆上分配结构?

mrn*_*ver 9 rust

在这段代码...

struct Test { a: i32, b: i64 }
    
fn foo() -> Box<Test> {              // Stack frame:
    let v = Test { a: 123, b: 456 }; // 12 bytes
    Box::new(v)                      // `usize` bytes (`*const T` in `Box`)
}
Run Code Online (Sandbox Code Playgroud)

...据我所知(忽略可能的优化),v在堆栈上分配然后复制到堆中,然后以Box.

而这段代码...

fn foo() -> Box<Test> {
    Box::new(Test { a: 123, b: 456 })
}
Run Code Online (Sandbox Code Playgroud)

...应该没有任何不同,大概是因为应该有一个用于结构分配的临时变量(假设编译器对内部的实例化表达式没有任何特殊语义Box::new())。

我发现返回位置的值总是在父堆栈帧或接收框中分配吗?. 关于我的具体问题,它只提出实验性box语法,但主要讨论编译器优化(复制省略)。

所以我的问题仍然存在:使用稳定的Rust,如何struct在不依赖编译器优化的情况下直接在堆上分配s?

mca*_*ton 9

您似乎正在寻找该box_syntax功能,但是从 Rust 1.39.0 开始,它不稳定,只能在夜间编译器中使用。这个功能似乎也不会很快稳定下来,如果稳定下来,可能会有不同的设计。

在夜间编译器上,您可以编写:

#![feature(box_syntax)]

struct Test { a: i32, b: i64 }

fn foo() -> Box<Test> {
    box Test { a: 123, b: 456 }
}
Run Code Online (Sandbox Code Playgroud)


mrn*_*ver 8

从 Rust 1.39 开始,似乎只有一种稳定的方法可以直接在堆上分配内存 - 通过使用 std::alloc::alloc(请注意,文档声明它预计将被弃用)。这是相当不安全的。

例子:

#[derive(Debug)]
struct Test {
    a: i64,
    b: &'static str,
}

fn main() {
    use std::alloc::{alloc, dealloc, Layout};

    unsafe {
        let layout = Layout::new::<Test>();
        let ptr = alloc(layout) as *mut Test;

        (*ptr).a = 42;
        (*ptr).b = "testing";

        let bx = Box::from_raw(ptr);

        println!("{:?}", bx);
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法用于不稳定的方法 Box::new_uninit

事实证明,甚至还有一个用于避免memcpy调用的板条箱(除其他外):copyless。这个 crate 也使用了一种基于此的方法。

  • 难道不应该使用 [`std::ptr::write`](https://doc.rust-lang.org/std/ptr/fn.write.html) 而不是使用 `=` 进行赋值以不删除该位置的旧值? (2认同)
  • 当此代码构造对字段“a”和“b”的引用时尝试为“a”和“b”分配值时,会导致未定义的行为,但其中包含未初始化的垃圾。在[原始引用](https://rust-lang.github.io/rfcs/2582-raw-reference-mir-operator.html)稳定之前,无法正确执行此操作。 (2认同)