copy
参考文档
copy - C++ Reference (cplusplus.com)
函数说明
将区间[first, last)内的元素复制到result指向的内存地址开始的内存区域中
函数声明
template <class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result);
底层实现
其实现与以下代码等价
template<class InputIterator, class OutputIterator>
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
while (first!=last) {
*result = *first;
++result; ++first;
}
return result;
}
返回值
一个指向复制的元素末尾的迭代器
测试实例
// copy algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::copy
#include <vector> // std::vector
int main () {
int myints[]={10,20,30,40,50,60,70};
std::vector<int> myvector (7);
std::copy ( myints, myints+7, myvector.begin() );
std::cout << "myvector contains:";
for (std::vector<int>::iterator it = myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
代码输出
myvector contains: 10 20 30 40 50 60 70
uninitialized_copy
参考文档
uninitialized_copy - C++ Reference (cplusplus.com)
std uninitialized_copy - 简书 (jianshu.com)
函数说明
将范围 [first,last) 中的元素的副本构造到从 result 开始的范围中,并将迭代器返回到目标范围中的最后一个元素。
与copy相比,result指向的内存区域无需预先申请堆空间
函数声明
template <class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_copy ( InputIterator first, InputIterator last,
ForwardIterator result );
底层实现
其实现与以下代码等价
template<class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_copy ( InputIterator first, InputIterator last,
ForwardIterator result )
{
for (; first!=last; ++result, ++first)
new (static_cast<void*>(&*result))
typename iterator_traits<ForwardIterator>::value_type(*first);
return result;
}
uninitialized_copy源码剖析
所有相关代码
uninitialized_copy
template<typename _InputIterator, typename _ForwardIterator>
inline _ForwardIterator
uninitialized_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
{
typedef typename iterator_traits<_InputIterator>::value_type
_ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type
_ValueType2;
#if __cplusplus < 201103L
const bool __assignable = true;
#else
// trivial types can have deleted assignment
typedef typename iterator_traits<_InputIterator>::reference _RefType1;
typedef typename iterator_traits<_ForwardIterator>::reference _RefType2;
const bool __assignable = is_assignable<_RefType2, _RefType1>::value;
#endif
return std::__uninitialized_copy < __is_trivial(_ValueType1)
&& __is_trivial(_ValueType2)
&& __assignable >::
__uninit_copy(__first, __last, __result);
}
typedef typename iterator_traits<_InputIterator>::value_type
_ValueType1;
typedef typename iterator_traits<_ForwardIterator>::value_type
_ValueType2;
typedef typename iterator_traits<_InputIterator>::reference _RefType1;
typedef typename iterator_traits<_ForwardIterator>::reference _RefType2;
以上四句利用iterator_traits获取输入迭代器和前向迭代器的数据类型,iterator_traits是一个存在特化的模板类,使用不同类去实例化该类,就会获得不同的迭代器类型
const bool __assignable = is_assignable<_RefType2, _RefType1>::value;
获取迭代器之间是否可赋值的信息
is_assignable<A, B>
获取类型B是否可以赋值给类型A
如果类型B重载了B&operator=(const A&); 则is_assiganable<A, B> = true;
反之则为false
return std::__uninitialized_copy < __is_trivial(_ValueType1)
&& __is_trivial(_ValueType2)
&& __assignable >::
__uninit_copy(__first, __last, __result);
is_trivial(_ ValueTypr1)
is_trivial函数的功能是判断一个元素是否为简单类型,那么什么是简单类型
-
简单类型(trivial type)包括标量类型(scalar type),简单类(trivial class)以及任何此类类型的数组
-
标量元素(scalar type)的相关概念可查看这篇文章 什么是标量类型(Scalar type) (biancheng.net)
-
简单类(trivial class)
-
构造函数,拷贝构造函数,移动构造函数,赋值运算符函数,移动赋值运算符函数和析构函数都为隐含的
-
没有虚成员
-
没有带大括号或相等初始化式的非静态数据成员
-
它的基类和非静态成员(如果有)也必须是简单类
-
-
__uninitialized_copy是一个有特化版本的仿函数,它会根据不同的布尔值运行不同版本的仿函数
__uninitialized_copy<false>
这是uninitialized_copy中条件判断失败执行的内容,直接在地址上执行std::_ Construct;
调用std::Construct、 addressof、 Destroy
template<bool _TrivialValueTypes>
struct __uninitialized_copy
{
template<typename _InputIterator, typename _ForwardIterator>
static _ForwardIterator
__uninit_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
{
_ForwardIterator __cur = __result;
__try
{
for (; __first != __last; ++__first, (void)++__cur)
std::_Construct(std::__addressof(*__cur), *__first);
return __cur;
}
__catch(...)
{
std::_Destroy(__result, __cur);
__throw_exception_again;
}
}
};
Construct(A,B)的功能:A为一个地址值,B为一个类对象或一个类对象的引用, Construct会将在A指向的位置上构造一个与B相同的类对象
__adressof(A)的功能:获取一个对象的地址值,即使其&(地址操作符)已经被重载
__uninitialized_copy<true>
调用std::copy完成具体操作部分
template<>
struct __uninitialized_copy<true>
{
template<typename _InputIterator, typename _ForwardIterator>
static _ForwardIterator
__uninit_copy(_InputIterator __first, _InputIterator __last,
_ForwardIterator __result)
{ return std::copy(__first, __last, __result); }
};
copy_backward
参考文档
copy_backward - C++ Reference (cplusplus.com)
函数说明
它会像copy()那样复制元素,但是从最后一个元素开始直到第一个元素
copy_backward()会复制前两个迭代器参数指定的序列
函数声明
template <class BidirectionalIterator1, class BidirectionalIterator2>
BidirectionalIterator2 copy_backward (BidirectionalIterator1 first,
BidirectionalIterator1 last,
BidirectionalIterator2 result);
示意图
如图所示,源序列from的最后一个元素是如何先被复制到目的序列to的最后一个元素的。从源序列的方向,将每一个元素依次复制到目的序列的前一个元素之前的位置。在进行这个操作之前,但也可以有更多。copy_backward()算法会返回一个指向最后一个被复制元素的迭代器,在目的序列的新位置,它是一个开始迭代器。
参数列表
目的序列的结束迭代器,通过将源序列中的最后一个函数复制到目的序列的结束迭代器之前。源序列会被复制到目的序列中
copy_backward()的3个参数都必须是可以自增自减的双向迭代器,这意味着这个算法只能应用到序列容器的序列上
返回值
一个指向copy的元素中的第一个元素的迭代器
底层实现
其实现与以下代码等价
template<class BidirectionalIterator1, class BidirectionalIterator2>
BidirectionalIterator2 copy_backward ( BidirectionalIterator1 first,
BidirectionalIterator1 last,
BidirectionalIterator2 result )
{
while (last!=first) *(--result) = *(--last);
return result;
}
copy_backward与copy对比
在序列重叠时,可以用copy()将元素复制到重叠的目的序列剩下的位置—也就是目的序列第一个元素之前的位置。如果想尝试用copy()算法将元素复制到同一个序列的右边,这个操作不会成功,因为被复制的元素在复制到同一个序列的右侧,这个操作不会成功,因为被复制的元素在复制之前会被重写。如果想将它们复制到右边,可以使用copy_backward(),只要目的序的结束迭代器在源序列的结束迭代器的右边
下图 说明了在将元素复制到重叠的序列的右边时,这两个算法的不同。
上图展示了在序列右边的前三个位置运用copy()和copy_backward()算法的结构。在想将元素复制到右边时,copy() 算法显然不能如我们所愿,因为一些元素在复制之前会被重写。在这种情况下,copy_backward() 可以做到我们想做的事。相反在需要将元素复制到 序列的左边时,copy() 可以做到,但 copy_backward() 做不到。
使用实例
std::deque<string> song{"jingle", "bells", "jingle","all","the","way"
};
song.resize(song.size()+2);//给deque多分配两个元素的空间
std::copy_backward(begin(song), begin(song)+6, end(song));
std::copy(begin(song), end(song), ostream iterator<string>(cout, " "));
cout << endl;
这段代码的输出如下:
jingle bells jingle bells jingle all the way