iter_swap()与swap() - 有什么区别?

Meh*_*dad 41 c++ swap

MSDN说:

swap应该优先使用iter_swap,它包含在C++标准中以便向后兼容.

但是comp.std.c ++说:

大多数STL算法在迭代器范围上运行.因此,iter_swap在这些范围内交换元素时使用是有意义的,因为这是它的预期目的 - 交换两个迭代器指向的元素.这允许优化基于节点的序列,例如std::list,节点只是重新链接,而不是实际交换的数据.

哪一个是正确的?我应该使用iter_swap,还是应该使用swap?(iter_swap仅用于向后兼容吗?)为什么?

Ruf*_*ind 26

该标准本身很少提及iter_swap:

  • swap(*a, *b)虽然没有规定必须以这种方式实施,但它应具有效果.
  • 取消引用值*a*b必须是"交换",这意味着swap(*a, *b)必须是有效的,因此,取消引用的类型必须相同,但迭代器类型没有要.
  • iter_swap需要在执行中使用std::reverse.对任何其他算法都没有这样的要求,所以这看起来很奇怪.

借用什么sehe发现了来自SGI文档:

严格来说,iter_swap是多余的.它仅出于技术原因而存在:在某些情况下,某些编译器难以执行解释所需的类型推导swap(*a, *b).

所有这些似乎都表明它是过去的神器.


Lig*_*ica 17

这似乎是互联网产生大量冲突信息的场景之一.

标准下面[C++11: 25.3.3/5]只说iter_swap(a,b)有结果swap(*a,*b)(并要求" a并且b应该可以解除引用",并且" *a应该可以交换*b"),这一点乍一看与MSDN的解释相关.

但是,我认为微软忽略了考虑as-if规则,这应该允许实现iter_swapswap某些情况下更快(例如链表的元素).

因此,我相信comp.std.c++引用在技术上更准确.

话虽如此,对可执行的优化存在相当严格的限制.例如,考虑一个iter_swap简单地重新链接节点而不是物理地交换元素值的过度链接列表元素的实现- 这不是一个有效的实现,因为违反了iter_swap可观察行为匹配的要求swap.

因此,我建议在实践中可以有一点,如果到宁愿任何好处iter_swapswap,我建议你坚持后者的简单性和一致性.swap无论如何,C++ 11移动语义应该在许多情况下变得很容易.

  • 所以我才意识到,如果`iter_swap`重新链接节点,`iter_swap`和`swap`不会产生相同的效果.如果`iter_swap`重新链接节点,那么指向旧对象的*指针*仍将指向同一个对象,而在`swap`的情况下,它们将引用新对象.那是一个有效的实现吗?或者是仅仅调用`swap`的唯一现实实现? (4认同)

Pot*_*ter 10

是的,如果使用得当,它们都会做同样的事情.不,std::iter_swap不推荐使用(通过置于标准的§D 兼容性功能部分).MSDN的引言误导性地不屑一顾.问题是使用std::swap不当是不方便的.

你应该使用iter_swap它的原因很简单,它是一个更高的抽象.

swap通常为用户定义的类型重载.调用它的正确方法是

using std::swap;
swap( blah, bleh );
Run Code Online (Sandbox Code Playgroud)

不是简单的

std::swap( blah, bleh );
Run Code Online (Sandbox Code Playgroud)

这在第17.6.3.2节中有所体现,特别是3:

其中swap(t, u)swap(u, t)被评估的上下文应确保在候选集上通过重载解析(13.3)选择名为"swap"的二进制非成员函数,该候选集包括:

- (20.2)和中swap定义的两个函数模板<utility>

- 由参数依赖查找(3.4.2)生成的查找集.

iter_swap不是这样一个特殊的重载名称,并且自定义其功能需要添加模板特化namespace std {}.


因此,有iter_swap用地封装了每次都可以实现的Swappable接口部分.

它实际上是一个更友好的接口,无论您的实现及其特定参数是否存在语义差异.(并不是应该忽略对它的潜在优化.MSDN可能会发表意见,但他们无法预测库作者可能使用"向后兼容性接口"提供什么.)


至于iter_swap具有明显不同结果的专业化swap( *a, *b ),这似乎与要求§25.3.3/ 5不一致,

效果:swap(*a, *b).

你举的例子听起来像是一个可观察的区别,因为指针*a*b前和术后都有效.不幸的是,这是库实现中的一个错误.


Old*_*Pro 5

您已达到关键区别。

swap(*a, *b)是一个全局函数,它将所有指向的指针重置*a为指向其内容,*b反之亦然。这是老tmp = aa = bb = tmp交换。

iter_swap仅在有限的情况下修改正在迭代的基础对象以影响它们所组成的结构。如果*a*b是同一链接列表的一部分,那么iter_swap只需交换它们在列表中的位置就足够了。当您只想对列表进行简单排序而不使列表中的对象的外部指针无效/更改时,这是一个优势。如果我有一个指向user对象的指针,则不在乎是否listuser对象进行排序,那么我不希望更改谁是“当前”用户的想法,因此最好不要使用列表排序swap