C++修改序列操作—移动、交换(move;move_backward;swap;swap_ranges;iter_swap)

一、move

头文件algorithm

template <class InputIterator, class OutputIterator>
  OutputIterator move (InputIterator first, InputIterator last, OutputIterator result);

移动元素范围

将[first,last]范围内的元素移动到从result开始的范围。

[first,last]中元素的值被传递给result指向的元素。 调用之后,[first,last]范围内的元素将保持未指定但有效的状态。

范围不应以结果指向[first,last]范围内的元素的方式重叠。 对于此类情况,请参阅move_backward。

此函数模板的行为等效于:

template<class InputIterator, class OutputIterator>
  OutputIterator move (InputIterator first, InputIterator last, OutputIterator result)
{
  while (first!=last) {
    *result = std::move(*first);
    ++result; ++first;
  }
  return result;
}

参数

  1. first,last
    将迭代器输入到要移动的序列中的初始位置和最终位置。 使用的范围是[first,last),它包含first和last之间的所有元素,包括first指向的元素,但不包括last指向的元素。
  2. result
    将迭代器输出到目标序列中的初始位置。这不应指向[first,last]范围内的任何元素。

返回值

到目标范围末尾的迭代器,其中元素已被移动。

// move algorithm example
#include <iostream>     // std::cout
#include <algorithm>    // std::move (ranges)
#include <utility>      // std::move (objects)
#include <vector>       // std::vector
#include <string>       // std::string

int main () {
  std::vector<std::string> foo = {"air","water","fire","earth"};
  std::vector<std::string> bar (4);

  // moving ranges:
  std::cout << "Moving ranges...\n";
  std::move ( foo.begin(), foo.begin()+4, bar.begin() );

  std::cout << "foo contains " << foo.size() << " elements:";
  std::cout << " (each in an unspecified but valid state)";
  std::cout << '\n';

  std::cout << "bar contains " << bar.size() << " elements:";
  for (std::string& x: bar) std::cout << " [" << x << "]";
  std::cout << '\n';

  // moving container:
  std::cout << "Moving container...\n";
  foo = std::move (bar);

  std::cout << "foo contains " << foo.size() << " elements:";
  for (std::string& x: foo) std::cout << " [" << x << "]";
  std::cout << '\n';

  std::cout << "bar is in an unspecified but valid state";
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

复杂度

第一个和最后一个之间的距离线性:对范围中的每个元素执行移动分配。

数据范围

两个范围中的对象都已修改。

异常

如果元素移动赋值或迭代器上的操作抛出则抛出。
请注意,无效参数会导致未定义的行为。

二、move_backward

头文件algorithm

template <class BidirectionalIterator1, class BidirectionalIterator2>
  BidirectionalIterator2 move_backward (BidirectionalIterator1 first,
                                        BidirectionalIterator1 last,
                                        BidirectionalIterator2 result);

向后移动元素范围

将结束时从[end,last]开始的元素移动到结束时终止的范围内。

该函数将迭代器返回到目标范围中的第一个元素。

结果范围的元素与[first,last]的顺序完全相同。 要颠倒他们的顺序,请参阅反向。

该函数首先将*(last-1)移动到*(result-1)中,然后通过前面的元素向后移动,直到第一次到达(并包括它)。

范围不应该以这样的方式重叠:结果(目标范围中的过去元素)指向范围内的元素(first,last)。对于这种情况,请参见move。

此函数模板的行为等效于:

template<class BidirectionalIterator1, class BidirectionalIterator2>
  BidirectionalIterator2 move_backward ( BidirectionalIterator1 first,
                                         BidirectionalIterator1 last,
                                         BidirectionalIterator2 result )
{
  while (last!=first) *(--result) = std::move(*(--last));
  return result;
}

参数

  1. first,last
    双向迭代器到要移动的序列中的初始和最终位置。 使用的范围是[first,last),它包含first和last之间的所有元素,包括first指向的元素,但不包括last指向的元素。
  2. result
    双向迭代器到目标序列中的过去位置。
    这不应指向范围内的任何元素(第一个,最后一个)。

返回值

到目标序列的第一个元素的迭代器,其中元素已被移动。

// move_backward example
#include <iostream>     // std::cout
#include <algorithm>    // std::move_backward
#include <string>       // std::string

int main () {
  std::string elems[10] = {"air","water","fire","earth"};

  // insert new element at the beginning:
  std::move_backward (elems,elems+4,elems+5);
  elems[0]="ether";

  std::cout << "elems contains:";
  for (int i=0; i<10; ++i)
    std::cout << " [" << elems[i] << "]";
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

复杂度

第一个和最后一个之间的距离线性:对范围中的每个元素执行移动分配。

数据范围

两个范围中的对象都已修改。

三、swap

头文件C++98: algorithm,C++11:utility
【C++ 98】

template <class T> void swap (T& a, T& b);

【C++ 11】

header	
// moved from <algorithm> to <utility> in C++11
non-array (1)	
template <class T> void swap (T& a, T& b)
  noexcept (is_nothrow_move_constructible<T>::value && is_nothrow_move_assignable<T>::value);
array (2)	
template <class T, size_t N> void swap(T (&a)[N], T (&b)[N])
  noexcept (noexcept(swap(*a,*b)));

交换两个对象的值。
【C++98】

此函数模板的行为等效于:

template <class T> void swap ( T& a, T& b )
{
  T c(a); a=b; b=c;
}

请注意该函数如何涉及复制构造和两个赋值操作,这可能不是交换存储大量数据的类的内容的最有效方式,因为这些操作中的每一个通常在其大小上以线性时间操作。

大型数据类型可以提供此函数的重载版本,从而优化其性能。 值得注意的是,所有标准容器都以这样的方式对其进行专门化处理,即只交换少量内部指针而不是整个内容,使它们在恒定时间内运行。
【C++11】
此函数不再在头algorithm中定义,而是在utility中定义。
这些函数模板的行为等同于:

template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])
{
  for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}

标准库的许多组件(在std中)以非限定方式调用swap以允许调用非基本类型的自定义重载而不是此通用版本:交换的自定义重载在与它们所属的类型相同的命名空间中声明 提供通过依赖于参数的查找来选择此通用版本。

参数

a,b
两个对象,其内容被交换。
【C ++98】
类型T应是可复制构造和可分配的。
【C++11】
类型T应是可移动构造和可移动分配的(或者为版本(2)定义交换)。

返回值

没有

// swap algorithm example (C++98)
#include <iostream>     // std::cout
#include <algorithm>    // std::swap
#include <vector>       // std::vector

int main () {

  int x=10, y=20;                              // x:10 y:20
  std::swap(x,y);                              // x:20 y:10

  std::vector<int> foo (4,x), bar (6,y);       // foo:4x20 bar:6x10
  std::swap(foo,bar);                          // foo:6x10 bar:4x20

  std::cout << "foo contains:";
  for (std::vector<int>::iterator it=foo.begin(); it!=foo.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

复杂度

非数组:常量:完全执行一个构造和两个赋值(尽管注意每个操作都依赖于它自己的复杂性)。
数组:N中的线性:每个元素执行交换操作。

数据范围

a和b都被修改。

异常

如果类型T的构造或赋值抛出则抛出。
如果T不是可移动构造且不可移动可分配,则永远不会抛出。
请注意,如果T不满足上面指定的要求(在参数中),则会导致未定义的行为。

四、swap_ranges

头文件algorithm

template <class ForwardIterator1, class ForwardIterator2>
  ForwardIterator2 swap_ranges (ForwardIterator1 first1, ForwardIterator1 last1,
                                ForwardIterator2 first2);

交换两个范围的值

将[first1,last1]范围内的每个元素的值与first2开始范围内各自元素的值进行交换。

该函数调用swap(非限定)来交换元素。

此函数模板的行为等效于:

template<class ForwardIterator1, class ForwardIterator2>
  ForwardIterator2 swap_ranges (ForwardIterator1 first1, ForwardIterator1 last1,
                                ForwardIterator2 first2)
{
  while (first1!=last1) {
    swap (*first1, *first2);
    ++first1; ++first2;
  }
  return first2;
}

参数

  1. first1,last1
    将迭代器转发到要交换的序列之一的初始位置和最终位置。 使用的范围是[first1,last1],它包含first1和last1之间的所有元素,包括first1指向的元素,但不包括last1指向的元素。
  2. first2
    将迭代器转发到要交换的其他序列中的初始位置。 使用的范围包括与范围[first1,last1]相同数量的元素。
    两个范围不得重叠。

范围不得重叠。 swap应定义为以对称方式(两个顺序)交换两个迭代器类型所指向的类型。

返回值

在第二个序列中交换的最后一个元素的迭代器。

// swap_ranges example
#include <iostream>     // std::cout
#include <algorithm>    // std::swap_ranges
#include <vector>       // std::vector

int main () {
  std::vector<int> foo (5,10);        // foo: 10 10 10 10 10
  std::vector<int> bar (5,33);        // bar: 33 33 33 33 33

  std::swap_ranges(foo.begin()+1, foo.end()-1, bar.begin());

  // print out results of swap:
  std::cout << "foo contains:";
  for (std::vector<int>::iterator it=foo.begin(); it!=foo.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "bar contains:";
  for (std::vector<int>::iterator it=bar.begin(); it!=bar.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

复杂度

第一个和最后一个之间的距离线性:对范围中的每个元素执行交换操作。

数据范围

两个范围中的对象都已修改。

五、iter_swap

头文件algorithm

template <class ForwardIterator1, class ForwardIterator2>
  void iter_swap (ForwardIterator1 a, ForwardIterator2 b);

两个迭代器指向的对象的交换值

交换a和b指向的元素。

该函数调用swap(非限定)来交换元素。

此函数模板的行为等效于:

template <class ForwardIterator1, class ForwardIterator2>
  void iter_swap (ForwardIterator1 a, ForwardIterator2 b)
{
  swap (*a, *b);
}

参数

a,b
将迭代器转发给要交换的对象。
swap应定义为交换迭代器指向的类型的值。

返回值

没有

// iter_swap example
#include <iostream>     // std::cout
#include <algorithm>    // std::iter_swap
#include <vector>       // std::vector

int main () {

  int myints[]={10,20,30,40,50 };              //   myints:  10  20  30  40  50
  std::vector<int> myvector (4,99);            // myvector:  99  99  99  99

  std::iter_swap(myints,myvector.begin());     //   myints: [99] 20  30  40  50
                                               // myvector: [10] 99  99  99

  std::iter_swap(myints+3,myvector.begin()+2); //   myints:  99  20  30 [99] 50
                                               // myvector:  10  99 [40] 99

  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

在这里插入图片描述

复杂度

常量:调用一次交换。

数据范围

两个迭代器指向的对象都被修改。

异常

如果对swap的调用抛出则抛出。
请注意,无效参数会导致未定义的行为。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
std::move_backward是C++标准库中的一个函数,用于将一个范围内的元素从后往前移动到另一个位置。它的函数签名如下: template <class BidirectionalIterator1, class BidirectionalIterator2> BidirectionalIterator2 move_backward (BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result); 其中,first和last是要移动的元素范围的迭代器,result是目标范围的结尾迭代器。这个函数将[first, last)范围内的元素按逆序移动到[result - (last - first), result)的位置上。 在移动的过程中,std::move_backward会调用元素的移动构造函数或移动赋值运算符来完成移动操作。这意味着移动过程中不会进行任何的复制操作,只是将原始范围内的元素转移至目标范围。 需要注意的是,如果目标范围的结尾在源范围内(即d_last在(first, last]内),则此行为是未定义的。在这种情况下,必须使用std::move代替std::move_backward来确保正确的行为。 下面是一个示例代码,展示了std::move_backward的用法: #include <iostream> #include <algorithm> #include <vector> #include <string> int main() { std::vector<std::string> src{"foo", "bar", "baz"}; std::vector<std::string> dest(src.size()); std::move_backward(src.begin(), src.end(), dest.end()); std::cout << "src: "; for (const auto &s : src) { std::cout << s << ' '; } std::cout << "\ndest: "; for (const auto &s : dest) { std::cout << s << ' '; } std::cout << '\n'; return 0; } 这段代码中,我们先创建了一个源范围src和一个目标范围dest,分别存储了一些字符串。然后,我们调用std::move_backward将src范围内的元素移动到dest范围的结尾。 最后,我们打印出移动前的src和dest范围的元素,以及移动后的结果。你可以看到,移动操作成功地将src范围内的元素按逆序移动到了dest范围的结尾处。 总结起来,std::move_backward是一个非常有用的函数,可以方便地将范围内的元素从后往前移动到另一个位置。它在一些特定的场景下特别适用,比如在处理重叠范围时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值