在这段代码中...

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`)
}

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

这个代码...

fn foo() -> Box<Test> {
    Box::new(Test { a: 123, b: 456 })
}

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

我找到了Do values in return position always get allocated in the parents stack frame or receiving Box?个.关于我的具体问题,它只提出了实验性的box语法,但主要讨论了编译器优化(复制省略).

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

推荐答案

从Rust 1.39开始,在stable中,似乎只有一种方法可以直接在堆上分配内存——使用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);
    }
}

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

事实证明,甚至有一个 crate 可以避免memcpy次呼叫(其中包括其他事情):copyless次.这个 crate 也使用基于此的方法.

Rust相关问答推荐

收集RangeInclusive T到Vec T<><>

两个相关特征的冲突实现错误

MutexGuard中的过滤载体不需要克隆

rust 迹-内存管理-POP所有权-链表

为什么reqwest以文本形式下载二进制文件?

如何go 除铁 rust 中路径组件的第一项和最后一项?

除了调用`waker.wake()`之外,我如何才能确保future 将再次被轮询?

你能在Rust中弃用一个属性吗?

这是什么:`impl Trait for T {}`?

为相同特征的特征对象使用 move 方法实现特征

为什么 GAT、生命周期和异步的这种组合需要 `T: 'static`?

Option<&T> 如何实现复制

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

Rust与_有何区别?

Rust typestate 模式:实现多个状态?

有没有办法隐式绑定 let/match 操作的成员?

从 Cranelift 发出 ASM

匹配结果时的简洁日志(log)记录

为什么我可以从读取的可变自引用中移出?

函数参数的 Rust 功能标志