box关键字有什么作用? [英] What does the box keyword do?

查看:49
本文介绍了box关键字有什么作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Rust 中,我们可以使用 Box 类型在堆上分配东西.此类型用于安全地抽象指向堆内存的指针.Box 由 Rust 标准库提供.

In Rust, we can use the Box<T> type to allocate things on the heap. This type is used to safely abstract pointers to heap memory. Box<T> is provided by the Rust standard library.

我很好奇Box<T>分配是如何实现的,所以我找到了其源代码.这是 Box::new 的代码(从 Rust 1.0 开始):

I was curious about how Box<T> allocation is implemented, so I found its source code. Here is the code for Box<T>::new (as of Rust 1.0):

impl<T> Box<T> {
    /// Allocates memory on the heap and then moves `x` into it.
    /// [...]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline(always)]
    pub fn new(x: T) -> Box<T> {
        box x
    }
}

实现中唯一的一行返回值 box x.这个box关键字在官方文档中没有任何解释;实际上它只是在 std::boxed 文档页面.

The only line in the implementation returns the value box x. This box keyword is not explained anywhere in the official documentation; in fact it is only mentioned briefly on the std::boxed documentation page.

推荐答案

注意: 这个回复有点旧.由于它讨论了内部结构和不稳定的功能,因此事情发生了一些变化.但基本机制保持不变,所以答案仍然能够解释box的潜在机制.

NOTE: This reply is a bit old. Since it talks about internals and unstable features, things have changed a little bit. The basic mechanism remains the same though, so the answer is still capable of explaining the undelying mechanisms of box.

box x 通常用什么来分配和释放内存?

What does box x usually uses to allocate and free memory?

答案是标有 lang 项 exchange_malloc 用于分配和 exchange_free 用于释放的函数.您可以在 heap.rs#L112heap.rs#L125.

The answer is the functions marked with lang items exchange_malloc for allocation and exchange_free for freeing. You can see the implementation of those in the default standard library at heap.rs#L112 and heap.rs#L125.

最后,box x 语法取决于以下语言项:

In the end the box x syntax depends on the following lang items:

  • owned_boxBox 结构上封装分配的指针.该结构体不需要 Drop 实现,它由编译器自动实现.
  • exchange_malloc 分配内存.
  • exchange_free 释放之前分配的内存.
  • owned_box on a Box struct to encapsulate the allocated pointer. This struct does not need a Drop implementation, it is implemented automatically by the compiler.
  • exchange_malloc to allocate the memory.
  • exchange_free to free the previously allocated memory.

这可以在 lang items 使用这个 no_std 示例的不稳定锈书的章节:

This can be effectively seen in the lang items chapter of the unstable rust book using this no_std example:

#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]

extern crate libc;

extern {
    fn abort() -> !;
}

#[lang = "owned_box"]
pub struct Box<T>(*mut T);

#[lang = "exchange_malloc"]
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
    let p = libc::malloc(size as libc::size_t) as *mut u8;

    // malloc failed
    if p as usize == 0 {
        abort();
    }

    p
}
#[lang = "exchange_free"]
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
    libc::free(ptr as *mut libc::c_void)
}

#[start]
fn main(argc: isize, argv: *const *const u8) -> isize {
    let x = box 1;

    0
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

注意 Drop 是如何没有为 Box 结构实现的?好吧,让我们看看为 main 生成的 LLVM IR:

Notice how Drop was not implemented for the Box struct? Well let's see the LLVM IR generated for main:

define internal i64 @_ZN4main20hbd13b522fdb5b7d4ebaE(i64, i8**) unnamed_addr #1 {
entry-block:
  %argc = alloca i64
  %argv = alloca i8**
  %x = alloca i32*
  store i64 %0, i64* %argc, align 8
  store i8** %1, i8*** %argv, align 8
  %2 = call i8* @_ZN8allocate20hf9df30890c435d76naaE(i64 4, i64 4)
  %3 = bitcast i8* %2 to i32*
  store i32 1, i32* %3, align 4
  store i32* %3, i32** %x, align 8
  call void @"_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE"(i32** %x)
  ret i64 0
}

allocate (_ZN8allocate20hf9df30890c435d76naaE) 按预期调用以构建 Box,同时...看!Box (_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE) 的 Drop 方法!让我们看看这个方法的 IR:

The allocate (_ZN8allocate20hf9df30890c435d76naaE) was called as expected to build the Box, meanwhile... Look! A Drop method for the Box (_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE)! Let's see the IR for this method:

define internal void @"_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE"(i32**) unnamed_addr #0 {
entry-block:
  %1 = load i32** %0
  %2 = ptrtoint i32* %1 to i64
  %3 = icmp ne i64 %2, 2097865012304223517
  br i1 %3, label %cond, label %next

next:                                             ; preds = %cond, %entry-    block
  ret void

cond:                                             ; preds = %entry-block
  %4 = bitcast i32* %1 to i8*
  call void @_ZN10deallocate20he2bff5e01707ad50VaaE(i8* %4, i64 4, i64 4)
  br label %next
}

就是这样,deallocate (ZN10deallocate20he2bff5e01707ad50VaaE) 在编译器生成的 Drop 上被调用!

There it is, deallocate (ZN10deallocate20he2bff5e01707ad50VaaE) being called on the compiler generated Drop!

注意标准库Drop 特性不是由用户代码实现的.事实上,Box 是一个有点神奇的结构.

Notice even on the standard library the Drop trait is not implemented by user-code. Indeed Box is a bit of a magical struct.

这篇关于box关键字有什么作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆