【问题标题】:What exactly does it mean to say a C++ object is movable?说 C++ 对象是可移动的究竟是什么意思?
【发布时间】:2021-01-02 18:23:54
【问题描述】:

给出以下定义:

  • object -- 一个连续的内存区域,保存某种类型的值。
  • value -- 根据对象类型解释的对象位。

C++ 编程语言书 [第 4 版] 的第 6.4.1 节在讨论值类别时指出:

Movable: 物体可以被移动(也就是说,我们可以移动 将其值转移到另一个位置并将对象保留在有效但 未指定的状态,而不是复制。

问题:

  1. “将其价值转移到另一个位置”的真正含义是什么?
  2. 如何移动值(位解释)?
  3. 如何在没有副本的情况下“移动”对象的字节?只是没有意义。

谁能解释一下?

【问题讨论】:

  • 请记住,这个“连续区域”可能包含指向存储在相关对象“外部”的其他数据的指针。 (参见字符串和向量)
  • 值不会被移动到另一个位置,但值和对象的所有权将被移动到新的所有者。
  • “移动”“拥有”任何包含的资源/生命周期的“副本”。例如,这可能是复制指针值而不是复制底层对象。这就是为什么捐赠者/来源处于“有效但未指定的状态”。
  • @ThomasMatthews 取决于被视为实例的内容。移出的对象仍然是对象。只是在设置为有效状态之前不应使用。
  • 有用的查看:youtube.com/watch?v=vLinb2fgkHk。您可能会认出演示者的名字。他回答了这个问题。

标签: c++ language-lawyer move-semantics


【解决方案1】:
  1. “将其价值转移到另一个位置”的真正含义是什么?

这意味着另一个位置具有原始位置在移动之前的价值,并且原始位置在移动之后具有什么价值并不重要。

  1. 如何移动值(位解释)?

例如,简单地通过复制。如果一个人想要做额外的工作(这不是仅仅用一袋位来激发的),可以将原始位置设置为其他位模式,例如全零,这仍然被认为是成功的举动。此处与复制的区别在于,副本应保持原件不变。

  1. 如何在没有副本的情况下“移动”对象的字节?只是没有意义。

副本是有效的移动。

有时原始中的位具有拥有资源的语义。如果只有 一个 资源,并且您只需复制位,那么现在 两个 位置都“拥有”该资源,导致当两个对象都用完时重复处置所述资源范围。

因此,移动会将资源的所有权转移到新位置,并将原始位置更改为不拥有资源。一个具体的例子是拥有指针:复制指针然后将原始指针设置为nullptr


副本可能比移动更昂贵(也可能不会)。但继续拥有指针的示例:如果您制作该对象的副本,那么在复制之后,必须存在两个资源(假设资源的唯一所有权)。

所以副本不会复制指针。副本复制资源,然后新位置指向新资源。如果创建该资源的成本很高,那么只需复制指针并将原始指针置空即可更便宜。


一般来说,当类型支持两种操作时,move应该是对copy的优化。搬家永远不应该比复制贵。如果 move 与 copy 具有相同的开销,则可以简单地不执行 move 操作,并且 copy 将无缝处理移动。由每种类型的作者来维护这种范式。

对于标量(整数、指针、双精度等),复制和移动是一回事:复制位,不要更改源。

【讨论】:

  • 谢谢。但为什么 Bjarne 说“而不是抄袭”?这就是我开始困惑的原因。
  • 移动而不是复制以使代码更高效。我已经更新了我的答案以反映这一点。
【解决方案2】:

移动物体”的行为类似于“卖房子 '。物体保持静止。只有所有权(所有权)易手。

在 C++ 中移动对象的概念是众所周知的“pass-by-reference”方法的实现之一。这可以通过一个真实的例子轻松解释。

互联网路由器是描述移动对象这一概念的最佳示例之一。假设有 4 个接口的路由器通过其中一个接口接收到一个数据包(IP 包)。现在,路由器必须先查找其路由表、应用安全策略、应用 NAT 规则等,然后才能将数据包从其接口之一发送出去。

路由器只会在内存中创建数据包的一份副本,并将其引用传递给不同的子系统(路由表、NAT、安全性、QoS 等)。 路由器的每个子系统将对数据包进行操作并将其传递给下一个子系统,直到数据包从路由器发送到目的地。 当数据包离开路由器时,内存将被清理。

在这种情况下,路由器的不同子系统在不同时间获得对同一数据包对象的控制权。数据包对象在整个处理过程中保持在单个内存位置。它永远不会被复制。这种将对象所有权传递给不同子系统/功能的方法可以看作是“移动对象”。然而,在实践中,对象一直停留在原来的位置,但对象的控制已跨子系统移动。

(类似于房子的所有权在出售时如何转移。)

【讨论】:

  • 引入“按引用传递”似乎并没有增加价值,尤其是因为这不是它的一般定义方式,尤其是现在它在 C++ 中的含义。即使“通过引用传递”被混淆为“通过对象共享调用”,它仍然不合适..
猜你喜欢
  • 1970-01-01
  • 2019-06-07
  • 2011-03-12
  • 2014-10-29
  • 2016-01-27
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多