【问题标题】:Should std::array have move constructor?std::array 应该有移动构造函数吗?
【发布时间】:2013-08-08 22:23:37
【问题描述】:

在 std::array 上不能有效地实现移动(O(1)),为什么它有移动构造函数?

【问题讨论】:

  • std::array 没有 任何 构造函数,除了编译器生成的默认值。
  • 你从哪里得到这条错误信息(std::array 有一个移动构造函数)?
  • @R.MartinhoFernandes 编译器生成的移动构造函数。
  • 仅仅因为移动整个数组不是 O(1) 并不意味着在移动每个元素时获得 O(1) 没有用。
  • 无益的答案是“当然 std::array 有一个 O(1) 移动构造函数”。 std::array<int, 5> 的所有实例化都需要相同的时间来移动/复制。 std::array<int, 6>?那是另一种类型!

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


【解决方案1】:

std::array 有一个编译器生成的移动构造函数,它允许将一个实例的所有元素移动到另一个实例中。如果元素可有效移动或仅可移动,这将很方便:

#include <array>
#include <iostream>

struct Foo
{
  Foo()=default;
  Foo(Foo&&)
  {
    std::cout << "Foo(Foo&&)\n";
  }
  Foo& operator=(Foo&&)
  {
    std::cout << "operator=(Foo&&)\n";
    return *this;
  }
};

int main()
{
  std::array<Foo, 10> a;
  std::array<Foo, 10> b = std::move(a);
}

所以我想说std::array 应该有一个移动复制构造函数,特别是因为它是免费提供的。没有一个需要它被主动禁用,我看不出有什么好处。

【讨论】:

  • 是否要求元素移动构造函数为nothrow?或者它可以简单地将操作留在任何合法状态?
  • @MarkB 好问题,我没有考虑过。这段代码在 gcc 4.7.3 上工作,即使我添加了一个复制构造函数。我将不得不阅读标准,但我的猜测是从一个容器到另一个容器的移动不能支持强异常保证。
  • @juanchopanza:我相信你在异常安全保证上是对的。也就是说,std::arraymove-constructor 没有提供强大的异常安全保证。只有最基本的。请参阅 12.8/15 的第一个项目符号。我唯一的疑问是“相应的子对象”是否也是一个右值。你怎么看?
  • @MarkB: "它是否要求元素移动构造函数不能被抛出?" 这是一个编译器生成的移动构造函数,因此它适用于给定的任何内容。如果底层类型是noexcept 可移动的,那么生成的移动构造函数也是。如果不是,那么生成的也不会是。
  • 答案不应该稍微多一些吗?尤其是堆栈上的数组(可能)不能进行指针交换,因此不能在 O(1) 中移动。移动构造函数隐式迭代聚合的元素并移动每个元素。这不是很明显,但是标准提供了这个强有力的保证,编译器在这里扩展了相当多的隐藏代码。
【解决方案2】:

总结和扩展其他答案,array&lt;T&gt; 应该是可移动的(当 T 本身是可移动的)因为:

  • T 可以有效地移动。
  • T 只能移动-

【讨论】:

  • 大声笑,这没什么。 “应该”“可能”“可能”......至少你的意思是标准的“应该”?
  • @v.oddou 这说明了为什么array&lt;T&gt; 可移动的(对于可移动的T)这一事实是有意义的。
  • @juanchopanza:这只是给圣诞老人的一封信。这在问题之前就已经很明显了。是的,我们想要所说的。现在我们想知道关于它是否存在以及为什么的事实
  • 哦,实际上,在重新阅读您的问题后,我现在明白了。问题是“应该”,因此答案重复了这个词,所以它本身就足够了。好的,通过了。大声笑
【解决方案3】:

看看标准:

23.3.2.2 数组构造函数、复制和赋值[array.cons]

应满足聚合条件 (8.5.1)。类数组 依赖于隐式声明的特殊成员函数(12.1, 12.4 和 12.8) 以符合 23.2 中的容器要求表。除了容器需求表中指定的需求外,隐式移动构造函数和移动赋值 数组运算符要求 T 为 MoveConstructible 或 MoveAssignable,分别。

移动构造函数和赋值运算符目前还不是免费的,可能没有提供。

【讨论】:

    猜你喜欢
    • 2014-05-02
    • 2012-06-12
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 2011-11-25
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多