【问题标题】:why should all iterators / iterator adaptors not-movable in C++11?为什么所有迭代器/迭代器适配器在 C++11 中都是不可移动的?
【发布时间】:2012-12-28 04:11:39
【问题描述】:

this 讨论的问题中何时在 C++11 中使类型不可移动,我发现 Scott Meyers 在comp.std.c++ 上有类似的问题,其中 SG 下面列出的类类型不是可在 C++11 库中移动。

  • 所有互斥锁类型(recursive_mutex、timed_mutex、recursive_timed_mutex、
  • 条件变量
  • type_info
  • error_category
  • locale::facet
  • random_device
  • seed_seq
  • reference_wrapper
  • 持续时间
  • 时间点
  • - 所有迭代器/迭代器适配器
  • ios_base
  • basic_istream::sentry
  • basic_ostream::sentry
  • 所有原子类型
  • once_flag

问题是为什么all iterators / iterator adaptors 不可移动?

【问题讨论】:

  • 这里一定有一个误解,因为迭代器的概念需要可复制性,这是对移动构造/赋值的改进。
  • @Mehrdad 准确地说,我偷了你的问题。
  • @billz:哈哈,确实,我注意到 =P 希望你能得到一个好的答案! :)
  • @Mehrdad 好吧,不幸的是,它建立在给定列表正确的假设之上。虽然这个问题仍然可以很好地伪造这个列表,因此无论如何都要 +1。

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


【解决方案1】:

该标准在批准前一年发布的帖子已经过时。海报是活跃的委员会成员 Daniel Krügler,有点政治游说:

这些是不可移动的,可能更多是偶然的,因为 隐式生成的移动操作的规则变得更加清晰 在匹兹堡会议上。已打开一般库问题

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1331

以应对图书馆缺乏移动支持。请确保您 联系你的国家机构代表,因为我有心,这 问题不足以替代国家机构的评论 反对 FCD。

换句话说,所有这些不可移动的类型对于标准来说都是一个引人注目的错误,他希望 Usenet 观众中的读者要求在标准正式发布之前解决问题。

“关闭”列表中的缺陷has been moved。解决方案是(为方便起见提供了链接):

查看规范的库部分并合并新添加的核心功能 Move Special Member Functions (N3044)。

由于 N3044 是一种大量的材料,因此很容易理解为什么要让这些基本功能正常工作是必不可少的。

迭代器,以及任何其他具有简单值语义的东西,如 std::durationstd::time_point肯定是可移动的。 正如其他人所提到的,可复制性意味着可移动性,如果它没有语言会被破坏。这篇文章当时并没有错;而是在争论未完成的语言的残缺。

【讨论】:

  • 现在这是对恕我直言问题的实际问题的一个很好的答案!
  • @ChristianRau 在阅读 Usenet 源代码之前我必须修复 URL……可能没有其他人真正关注该链接
  • +1 谢谢@Potatoswatter 如果可以的话,我会尝试点击链接,感谢您的指导。
  • 您能否澄清一下“可复制性意味着可移动性”的含义确切地?它如何应用于仅定义复制操作和析构函数的类?它如何应用于定义复制操作、析构函数和删除移动操作的类?我倾向于发现“可移动”一词不精确。这对我来说并不明显是什么意思。 “可移动”只是意味着您可以使用右值源构造 T(可能解析为复制 ctor)还是意味着实际调用了移动 ctor?
  • 我不明白“可复制性意味着可移动性”的东西。如果复制 ctor 是公开且显式的,但移动 ctor 是 deleted 且隐式怎么办?然后T a = std::move(b) 将失败,即使a 肯定是可复制的......
【解决方案2】:

我认为您在不可移动类型列表中包括:“将移动实现为普通复制的类”。 .迭代器被认为是复制成本低的轻量级对象。为他们指定一个移动操作员是没有意义的。例如。 std::vector<T>::iterator 本质上只是一个包装好的T*,复制它们就像搬家一样便宜。

【讨论】:

  • std::vector<T>::iterator 甚至不需要被包装,这使得问题的断言变得可疑。我没有点击 Usenet 的链接……
  • @Potatoswatter:至少对于T=bool,您需要将其包裹起来。 ;-) 无论如何,list<T>::iteratorlist_node<T>* 之类的包装器。
【解决方案3】:

关于迭代器的“不可移动”可能意味着类定义不包含用户声明的移动操作。但是迭代器仍然是可复制的。因此,移动请求仍然有效,并且依赖于复制。因此,在移动操作与复制操作完全相同的情况下,没有理由提供移动操作。对于典型的迭代器实现,没有什么可以针对 w.r.t 进行优化。移动。

【讨论】:

  • 对于输入迭代器来说,only 支持移动而不支持复制会更有意义。
【解决方案4】:

简答

因为它们是可复制的。

长答案

我们首先要弄清楚“移动”的真正含义。 冯纽曼机器不移动数据:你只是“复制”。数据从一个内存位置复制到另一个内存位置。从未“移动​​”过。

但在更高的抽象级别,数据可以只是指向其他数据的指针。当您复制一个使复制的指针无效的指针时,所引用的数据被称为从一个“所有者”“移动”到另一个“所有者”。

更一般地说,复制一个值(包含在指针中的地址)并销毁将其设置为可识别的“无效”的原始值的操作称为“移动”。

在 C++ 中,可以区分不同类型的对象:

  1. 只包含一个简单值的那些。
  2. 那些只包含一个简单的指针或引用,“拥有”它们所引用的内容
  3. 那些只包含一个简单的指针或引用而不是“欠”它们所引用的内容
  4. 包含巨大价值的那些。
  5. 代表物理实体或操作系统(更一般的“托管平台”)实体的实体。

对于所有这些类型,“复制”和“移动”的概念可能具有不同的语义含义,并且对于其中一些操作而言,一种或另一种操作可能根本就没有意义。

现在考虑类型 1 对象:

int a=5; c=0;
c = a;
c = std::move(a);

您希望a 在移动后的值是多少? c = a+b 呢? a 和 b 是否应该“移动”到 operator+ 中?

现在考虑输入 2 个对象:

std::unique_ptr<int> pa(new int(5)), pb;
pb = std::move(pa);

这里有两个智能指针(它们都将在范围退出时被销毁)并且只有一个整数。 有一种操作(在这种情况下为delete)只能执行一次,因此只有一个指针必须保留整数的“所有权”。这就是“复制”没有意义的情况,移动是唯一支持的操作

现在考虑类型 3 对象:

std::list<int> lst = { 1,2,3,4 };
auto i = lst.begin();
auto j = i; 
*j = *i+5;
++i;
*i = *j;

这很有意义:它只是使列表变为{ 6,6,3,4 }。 迭代器不拥有它们所指的内容:可能有许多迭代器都引用相同的值。复制有意义,但移动没有意义:如果我们将 i 移动到 j (复制),*i 和 ++i 将不再可能。

现在考虑类型 4 的对象:

class A
{
   int m[15000000]; //15 million integers
public:
   int& operator[](unsigned x) { return m[x]; }
   const int& operator[](unsigned x) const { return m[x]; }
};

如此巨大的野兽在大多数系统中分配到堆栈上都会有问题。它很可能会留在堆上,并由(智能)指针拥有/引用。它的地址将在其指针之间移动,但对象本身将不可移动。它可能仍然是可复制的。

还有另一种微妙的情况:当 A 本身是一个指向动态分配的巨大数组的指针时:这与 std::vector 相同:它是可移动的,因为它本身就是一个拥有动态分配数据的“智能指针” ,但也可能是可复制的,因为在某些情况下您可能需要拥有数据的新的不同副本。

现在考虑类型 5:

class window
{
private:
   HWND handle;
public:
   window() :handle(CreateWindow(....)) 
   { .... }
   ~window() { DestroyWindow(handle); }
};

这里window 的实例表示屏幕上存在的一个窗口。 “复制”或“移动”是什么意思?

mutexcondition_variable 等很可能是这种情况,其中复制和移动都被禁用。

【讨论】:

  • 如果您正在写较长的答案,您可以编写、发布、删除、取消删除,以防止其他人看到您未完成的帖子。
  • @Emilio 这个人就是我,只是投了反对票因为你发布了一个未完成的答案(因此我可以问你同样的问题;)),这是应该劝阻的行为(并且您的 "Short Answer" 不是那么清楚或解释,它可能适合作为评论)。我仍然认为没有理由评论我的反对票,因为 “答案” 的低质量非常明显,而且反对票很可能在不久的将来消失,无论如何(它已经有了)。
  • @ChristianRau:你对你的意见负有唯一责任,我也是我唯一的一个。唯一不同的是,我是事后写的。现在您谈论“低质量和其他废话”,但是在您玩过游戏之后,这些意见没有任何价值。恕我直言,你只是在说你必须说的话来证明你的偏见是正当的。就我个人而言,我发现 Redex 的评论更具建设性,但 - 再次 - 这只是我的意见
  • @EmilioGaravaglia “你对你的意见负有唯一责任,我也是我唯一的一个” - 成功了。因此,如果我对我认为质量差的答案投反对票,这是我的决定无论如何,这个反对票已经在消失的路上(如果不是它的原因会改变,并且根据现在完成的答案的实际内容编写不同的评论)。无论如何,我认为没有任何理由再投反对票了。
猜你喜欢
  • 1970-01-01
  • 2014-10-14
  • 2020-06-29
  • 2011-01-19
  • 2011-02-05
  • 2010-09-20
  • 2016-09-23
  • 2013-09-14
  • 2018-08-16
相关资源
最近更新 更多