【问题标题】:Understanding move semantics for std::array了解 std::array 的移动语义
【发布时间】:2015-03-11 14:05:59
【问题描述】:

我正在尝试理解移动语义,所以我做了以下测试:

#include <iostream>
#include <array>

using namespace std;

void tryToMove(array<double,3> && v) {
    array<double,3> v_ = std::move(v);
    std::cout << v_[0] << "  " << v_[1] << "  " << v_[2] <<'\n';
}

int main () {
    array<double,3> v{1,2,3};

    tryToMove(std::move(v));
    std::cout << v[0] << "  " << v[1] << "  " << v[2] <<'\n';
}

我预计主的 std::cout 中会出现分段错误,因为 v_ 应该移动到 tryToMove 中。但是,输出是:

1 2 3
1 2 3

这里到底发生了什么?

谢谢!

【问题讨论】:

  • 移动语义与分段错误有什么关系?你期待未定义的行为吗?如果是这样,未定义的行为不是“将始终崩溃”的代码。
  • 当您在某个对象上调用std::move 时,您必须假设它已被成功移出。该标准表示对象在移动后处于有效但未指定的状态,因此数组中的值不是确定性的。 std::array 的移动构造函数是隐式的,因此它只会复制底层数组,仅此而已。

标签: c++ c++11 move-semantics


【解决方案1】:

我期待一个分割错误

首先,获得段错误的大多数方法都是由于未定义的行为,在这种情况下任何事情都可能发生,您可能不应该期待任何事情具体的。

因为v_应该被移动

std::array 包含直接嵌入其中的元素(不在堆上,由指针引用,就像 std::vector 一样),因此您不能将其内容移动到任何地方。他们将永远在里面。

所以你所做的只是从旧数组初始化一个新数组,你没有移动任何东西。新数组的元素将由右值双精度数初始化,但这也不会移动任何东西,因为您不能“移动”双精度数(它也没有外部分配的数据要传输)。所以它只是每个元素的副本。

【讨论】:

  • 这些微妙的 C++ 东西害死我了。谢谢你的回答!
  • @JaviV 如果你想学习,我不会认为它很微妙。
  • @JaviV,一些类为移出的对象提供保证,但一般来说,除了分配给它或销毁它之外,你不能对它做任何事情。这是一个很好的经验法则。
  • @chris,我不同意这个经验法则,它比必要的要保守得多。
  • 如果我有一个从std::vector 搬来的人,例如,没有什么能阻止我打电话给clear() 并重复使用它。经验法则是“不要做任何有先决条件的事情,而不检查先决条件”。学习“除了分配和销毁之外什么都没有”并不难。
【解决方案2】:

问题在于,您预计会出现分段错误,只是因为您访问了不再属于您的内存。

未定义的行为意味着任何事情都可能发生。

在这种情况下,v 的状态是未指定的,因此您对它的三个元素的访问可能有效,也可能无效。当它们有效时(它们可能是因为在这种情况下可能会复制基础数据)你很好;当它们无效时,您不能简单地假设结果将是分段错误。操作系统要引发分段错误,必须具备一些条件:这不是检测错误的灵丹妙药。

【讨论】:

  • 但记忆是“你的”。
  • int 的移动没有​​明确指定吗?考虑到数组移动构造函数的语义,以及a.size() == Na 类型为array&lt;T, N&gt; 的不变量,对我来说似乎并非完全未指定。
  • 是的,一揽子“有效但未指定的状态”措辞说“除非另有说明”(无论如何这在整个标准中都是隐含的),std::array 的精确说明在我的书。
  • @JonathanWakely:不过,我更感兴趣的是帮助 OP 消除对 UB 的误解,而不是争论我们应该在多大程度上将实际扣除视为标准要求。 :)
  • 对于那些说“当然可以阅读条目”的人,double 的值可以包括标准下的陷阱表示,并且来自他们的moveing 可以设置@ 987654329@ 表示陷阱表示(哎呀,如果它在那里,在调试中这样做会很棒)。然后阅读可以做任何事情(如段错误或鼻恶魔)。写作将保持有效,arr.size() == N 等。
猜你喜欢
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
  • 2020-02-23
  • 2016-04-07
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多