框<X>与 X 上的移动语义 [英] Box<X> vs move semantics on X

查看:41
本文介绍了框<X>与 X 上的移动语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于 Box 的简单问题.我明白它的作用,它在堆上分配 X .在 C++ 中,您使用 new 运算符在堆上分配一些东西,这样它就可以在当前范围内存活(因为如果您在堆栈上创建了一些东西,它会在当前块的末尾消失).>

但是阅读 Rust 的文档,看起来你可以在堆栈上创建一些东西,并且仍然可以利用语言的移动语义返回它,而不必求助于堆.然后我不清楚什么时候使用 Box 而不是简单的 X.

我刚刚开始阅读 Rust,所以如果我遗漏了一些明显的东西,我深表歉意.

解决方案

首先: C++11(和更新版本)也有带有右值引用的移动语义.所以你的问题也适用于 C++.但请记住,C++ 的移动语义——与 Rust 的不同——非常不安全.

第二:移动语义"这个词以某种方式暗示没有副本",这是不正确的.假设您有一个带有 100 个 64 位整数的 struct.如果您将通过移动语义传输此结构的对象,则将复制这 100 个整数(当然,编译器的优化器通常可以删除这些副本,但无论如何......).当处理处理堆上某种数据(或一般的指针)的对象时,移动语义的优势就会发挥作用.

例如看一下Vec(类似于C++的vector):类型本身只包含一个指针和两个指针大小的整数(ptrlencap).当向量移动时,这三个 64 位仍然被复制,但向量的主要数据(位于堆上)没有被触及.

<小时>

话虽如此,让我们讨论主要问题:为什么要使用 Box?".实际上有很多用例:

  • 未调整大小的类型:某些类型(例如,还包括闭包的 Trait 对象)未调整大小,这意味着编译器不知道它们的大小.但是编译器必须知道每个堆栈帧的大小——因此那些未确定大小的类型不能存在于堆栈中.
  • 递归数据结构:想想一个 BinaryTreeNode 结构.它保存了两个名为left"和right"的成员,类型为... BinaryTreeNode?那行不通.因此,您可以将两个孩子都装箱,以便编译器知道您的结构的大小.
  • 巨大的结构:想想上面提到的 100 个整数结构.如果你不想每次都复制它,你可以在堆上分配它(这种情况很少发生).

I have an easy question regarding Box<X>. I understand what it does, it allocates X on the heap. In C++ you use the new operator to allocate something on the heap so it can outlive the current scope (because if you create something on the stack it goes away at the end of the current block).

But reading Rust's documentation, it looks like you can create something on the stack and still return it taking advantage of the language's move semantics without having to resort to the heap. Then it's not clear to me when to use Box<X> as opposed to simply X.

I just started reading about Rust so I apologize if I'm missing something obvious.

解决方案

First of all: C++11 (and newer) has move semantics with rvalue references, too. So your question would also apply to C++. Keep in mind though, that C++'s move semantics are -- unlike Rust's ones -- highly unsafe.

Second: the word "move semantic" somehow hints the absence of a "copy", which is not true. Suppose you have a struct with 100 64-bit integers. If you would transfer an object of this struct via move semantics, those 100 integers will be copied (of course, the compiler's optimizer can often remove those copies, but anyway...). The advantage of move semantics comes to play when dealing with objects that deal with some kind of data on the heap (or pointers in general).

For example, take a look at Vec (similar to C++'s vector): the type itself only contains a pointer and two pointer-sized integer (ptr, len and cap). Those three times 64bit are still copied when the vector is moved, but the main data of the vector (which lives on the heap) is not touched.


That being said, let's discuss the main question: "Why to use Box at all?". There are actually many use cases:

  • Unsized types: some types (e.g. Trait-objects which also includes closures) are unsized, meaning their size is not known to the compiler. But the compiler has to know the size of each stack frame -- hence those unsized types cannot live on the stack.
  • Recursive data structures: think of a BinaryTreeNode struct. It saves two members named "left" and "right" of type... BinaryTreeNode? That won't work. So you can box both children so that the compiler knows the size of your struct.
  • Huge structs: think of the 100 integer struct mentioned above. If you don't want to copy it every time, you can allocate it on the heap (this happens pretty seldom).

这篇关于框&lt;X&gt;与 X 上的移动语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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