swap
应该优先使用iter_swap
,它包含在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
.对任何其他算法都没有这样的要求,所以这看起来很奇怪.严格来说,
iter_swap
是多余的.它仅出于技术原因而存在:在某些情况下,某些编译器难以执行解释所需的类型推导swap(*a, *b)
.
所有这些似乎都表明它是过去的神器.
Lig*_*ica 17
这似乎是互联网产生大量冲突信息的场景之一.
cplusplus.com说这iter_swap
与以前的swap
逻辑完全相同,MSDN在说一个人应该坚持下去时是正确的swap
.
cppreference.com告诉我们,电话swap
只是一种可能实现的iter_swap
,开启了在可能的优化门iter_swap
某些特例,只要功能的不断复杂性担保维持原判.
标准下面[C++11: 25.3.3/5]
只说iter_swap(a,b)
有结果swap(*a,*b)
(并要求" a
并且b
应该可以解除引用",并且" *a
应该可以交换*b
"),这一点乍一看与MSDN的解释相关.
但是,我认为微软忽略了考虑as-if规则,这应该允许实现iter_swap
比swap
某些情况下更快(例如链表的元素).
因此,我相信comp.std.c++
引用在技术上更准确.
话虽如此,对可执行的优化存在相当严格的限制.例如,考虑一个iter_swap
简单地重新链接节点而不是物理地交换元素值的过度链接列表元素的实现- 这不是一个有效的实现,因为违反了iter_swap
可观察行为匹配的要求swap
.
因此,我建议在实践中可以有一点,如果到宁愿任何好处iter_swap
了swap
,我建议你坚持后者的简单性和一致性.swap
无论如何,C++ 11移动语义应该在许多情况下变得很容易.
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
前和术后都有效.不幸的是,这是库实现中的一个错误.
您已达到关键区别。
swap(*a, *b)
是一个全局函数,它将所有指向的指针重置*a
为指向其内容,*b
反之亦然。这是老tmp = a
,a = b
,b = tmp
交换。
iter_swap
仅在有限的情况下修改正在迭代的基础对象以影响它们所组成的结构。如果*a
和*b
是同一链接列表的一部分,那么iter_swap
只需交换它们在列表中的位置就足够了。当您只想对列表进行简单排序而不使列表中的对象的外部指针无效/更改时,这是一个优势。如果我有一个指向user
对象的指针,则不在乎是否list
对user
对象进行排序,那么我不希望更改谁是“当前”用户的想法,因此最好不要使用列表排序swap
。