std::反向使用反向迭代器,为什么不是无操作?

std::reverse with reverse iterators, why isn't it a no-op?

本文关键字:为什么不 操作 迭代器 std      更新时间:2023-10-16

举一个最小的例子:

#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string s{"abcde"};
std::reverse(s.rbegin(), s.rend());
std::cout << s;
}

由于我们正在反转一系列反向迭代器,我希望它是一个no-op。但它打印edcba。我对反向迭代器或std::reverse有什么不了解?

在这种情况下,交换操作是对称的,所以从s.begin()s.end()还是从s.rbegin()s.rend()都无关紧要。

为了可视化这一点,首先考虑前进时(从s.begin()s.end())会发生什么,使用abcde的示例:

  • ae。字符串现在是ebcda
  • bd。字符串现在是edcba

反转现在完成(c在中间,不需要移动)。

现在考虑向后(从s.rbegin()s.rend())会发生什么:

  • eabcda
  • db交换。字符串现在是edcba

最终结果是一样的,因为交换是对称的。

根据C++标准:

25.3.10反向[alg.Reverse]

template<class BidirectionalIterator>
void reverse(BidirectionalIterator first, BidirectionalIterator last);

效果:对于每个非负整数i < (last - first) / 2,将iter_swap应用于所有迭代器对first + i(last - i) - 1

算法对范围进行操作。std::reverse完成了它的工作,[s.rbegin()s.rend())现在是"abcde"std::cout << s;将从另一端打印它,所以"edcba".

还好,
最后使用了swap(*_Left,*_Right);因此它更改了原始字符串s
请参阅来源:

template<class _BidIt> inline
void reverse(_BidIt _First, _BidIt _Last)
{   // reverse elements in [_First, _Last)
_DEBUG_RANGE(_First, _Last);
_Reverse(_Unchecked(_First), _Unchecked(_Last), _Iter_cat(_First));
}
template<class _BidIt> inline
void _Reverse(_BidIt _First, _BidIt _Last, bidirectional_iterator_tag)
{   // reverse elements in [_First, _Last), bidirectional iterators
for (; _First != _Last && _First != --_Last; ++_First)
_STD iter_swap(_First, _Last);
}
template<class _FwdIt1,
class _FwdIt2> inline
void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right)
{   // swap *_Left and *_Right
swap(*_Left, *_Right);
}