码迷,mamicode.com
首页 > 编程语言 > 详细

STL简单 copy 算法的实现

时间:2016-06-12 03:29:34      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

1.简介

         不论是对客户端或对STL内部而言,copy() 都是一个常常被调用的函数。由于copy进行的是复制操作,而复制操作不外乎运用赋值运算符(assignment operator)或复制构造函数(copy constructor),但是某些元素的类型是trivial assignment operator,因此如果能使用内存直接进行复制(例如使用C标准函数memmove、memcpy),便能节约大量时间。为此,copy算法用尽各种办法,包括函数重载(function overloading)、型别特性(type traits)、偏特化(partial specialization)等编程技巧来加强效率。

         copy算法可将输入区间 [first, last ) 内的元素复制到输出区间 [ result, result + ( last – first ) )内,并返回迭代器:result + (last – first ) 。copy对template参数所要求的条件非常宽松,输入区间有InputIterator 构成,输出由OutputIterator 构成。

 技术分享

         由上图可知,copy算法从以下方面强化复制性能:

1.      迭代器指针类型,一般分为对象指针和原生指针。原生指针可直接使用memmove方式进行拷贝。像memmove这里的底层库函数,在汇编层面上做了优化,复制速度极快,有兴趣的童鞋请自行查阅相关资料;

2.      赋值运算符(assignment operator)类型,指针指向的对象,其赋值运算符可以分为trivial operator和non-trivial operator(trivial 和non-trivial 的概念请移步:stack overflowCSDN),trivial 赋值运算符之间调用memmove,non-trivial的比较悲剧,只能挨个复制;

3.      迭代器类型,分为InputIterator、RandomAccessIterator。InputIterator类型的需要由迭代器来判断复制结束,我们知道,判断iter != contianer.end()需要调用operator!=重载函数,速度慢。RandomAccessIterator以距离是否相等来决定复制结束,速度较快。

 

2.设计与实现

我用VS2013写的程序(github),数值算法的实现版本的位于cghSTL/version/ cghSTL-0.5.2.1.rar

本文介绍的算法实现需要以下文件:

1.    cghStl_algobase.h,本文的主角:算法的源码,位于cghSTL/algorithms/

2.    cghUtil.h:包含copy算法用到的memmove算法,位于cghSTL/cghUtil/

3.    cghSTL_type_traits.h,特性萃取机,可以判断对象是否为trivial或non-trivial;

4.    cghSTL_iterator.h,迭代器的基类,共五种,所有迭代器都要继承于这五种基类,继承自不同基类的迭代器,拥有不同特性,在算法实现中,性能也不一样;

5.    test_algorithms_algobase_copy.cpp,测试文件,位于cghSTL/test/

6.    cghVector.h,自己实现的vector,用于测试copy算法的容器,位于cghSTL/sequence containers/cghVector/想了解vector实现细节的同学请移步:STL简单vector的实现

7.    cghDeque.h,自己实现的deque,用于测试copy算法的容器,位于cghSTL/sequence containers/cghDeque/想了解vector实现细节的同学请移步:STL简单deque的实现

 

为了增强代码的可读性,我用region把各个算法隔开,如下图所示

技术分享

技术分享

         童鞋们可以借助上图和上上图来理解copy是框架和流程,直接上代码吧,注释已经说明了一切~

cghStl_algobase.h

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  chengonghao@yeah.net
*
*  文件内容:equal、fill、fill_n、iter_sawp、max、min、
			 lexicographical_compare、mismatch、copy 算法的实现
******************************************************************/


#ifndef _CGH_STL_ALGOBASE_
#define _CGH_STL_ALGOBASE_

#include "cghUtil.h"
#include "cghSTL_type_traits.h"
#include "cghSTL_iterator.h"

namespace CGH{
	#pragma region copy

#pragma region 第一层:copy 算法入口

	/* copy 算法唯一的对外接口(完全泛化版)*/
	template<class InputIterator, class OutputIterator>
	inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
	{
		return copy_dispatch<InputIterator, OutputIterator>()(first, last, result);
	}

	#pragma region copy的特化版(specialization)

	/* copy 算法针对const char* 版本的特化版 */
	inline char* copy(const char* first, const char* last, char* result)
	{
		// 采用 memmove 的方式直接复制数据,cgh_memmove 函数位于 cghUtil.h 文件
		cgh_memmove(result, first, last - first) ;
		return result + (last - first) ;
	}

	/* copy 算法针对const wchar_t* 版本的特化版 */
	inline wchar_t* copy(const wchar_t* first, const wchar_t* last, wchar_t* result)
	{
		// 采用 memmove 的方式直接复制数据,cgh_memmove 函数位于 cghUtil.h 文件
		cgh_memmove(result, first, sizeof(wchar_t) * (last - first)) ;
		return result + (last - first) ;
	}
	#pragma endregion

#pragma endregion

#pragma region 第二层:copy_dispatch
	template<class InputIterator, class OutputIterator>
	struct copy_dispatch{
		InputIterator operator()(InputIterator first, InputIterator last, OutputIterator result)
		{
			return _copy(first, last, result, CGH::iterator_category(first));
		}
	};

	#pragma region copy_dispatch 的偏特化版本

	/*
		在参数为原生指针的情况下,进一步探测指针指向的对象是否具有 trivial assignment operator
		assignment operator 对效率的影响不小
		1.如果指针指向的对象具有 non-trivial assignment operator,复制操作就必须通过 trivial assignment operator 进行
		2.如果指针指向的对象具有 trivial assignment operator,我们完全可以通过最快的内存拷贝(memmove进行)
	*/
	template<class T>
	struct copy_dispatch<T*, T*>{
		T* operator()(T* first, T* last, T* result)
		{
			// 通过特性萃取机(cghSTL_type_traits),获得对象 assignment operator 类型
			typedef typename cghSTL_type_traits<T>::has_trivial_assignment_operator	t;
			return _copy_t(first, last, result, t());
		}
	};

	/*
		在参数为原生指针的情况下,进一步探测指针指向的对象是否具有 trivial assignment operator
		assignment operator 对效率的影响不小
		1.如果指针指向的对象具有 non-trivial assignment operator,复制操作就必须通过 trivial assignment operator 进行
		2.如果指针指向的对象具有 trivial assignment operator,我们完全可以通过最快的内存拷贝(memmove进行)
	*/
	template<class T>
	struct copy_dispatch<const T*, T*>{
		T* operator()(T* first, T* last, T* result)
		{
			// 通过特性萃取机(cghSTL_type_traits),获得对象 assignment operator 类型
			typedef typename cghSTL_type_traits<T>::has_trivial_assignment_operator	t;
			return _copy_t(first, last, result, t());
		}
	};

	#pragma endregion

#pragma endregion

#pragma region 第三层
	template<class InputIterator, class OutputIterator>
	inline OutputIterator _copy(InputIterator first, InputIterator last, OutputIterator result, CGH::input_iterator_tag)
	{
		// 以迭代器是否到达末尾,决定循环结束,速度慢
		for (; first != last; ++result, ++first)
		{
			*result = *first ;
		}
		return result ;
	}

	template<class RandomAccessIterator, class OutputIterator>
	inline OutputIterator _copy(RandomAccessIterator first, RandomAccessIterator last, OutputIterator result, CGH::random_access_iterator_tag)
	{
		return _copy_d(first, last, result, distance_type(first)) ;
	}

	/* 如果对象拥有 non-trivial assignment operator 那么直接进行内存拷贝 */
	template<class T>
	inline T* _copy_t(const T* first, const T* last, T* result, true_type)
	{
		cgh_memmove(result, first, sizeof(T) * (last - first)) ;
		return result + (last - first) ;
	}

	/* 如果对象拥有 trivial assignment operator 那么调用_copy_d,用自定义的 assignment operator,挨个对象拷贝 */
	template<class T>
	inline T* _copy_t(const T* first, const T* last, T* result, false_type)
	{
		return _copy_d(first, last, result, (ptrdiff_t*)0);
	}

	template<class RandomAccessIterator, class OutputIterator, class Distance>
	inline OutputIterator _copy_d(RandomAccessIterator first, RandomAccessIterator last, OutputIterator result, Distance*)
	{
		// 以 n 决定循环次数,速度比用迭代器决定循环次数更高效
		for (Distance n = last - first; n > 0; --n, ++result, ++first)
		{
			*result = *first ;
		}
		return result ;
	}
#pragma endregion

	#pragma endregion
}

#endif


3.测试

Copy算法的测试工作量不小,要从一下方面入手:

1.      原生指针的测试;

2.      trivial和non-trivial 赋值运算符的测试;

3.      InputIterator、RandomAccessIterator迭代器;

 

测试环节的主要内容已在注释中说明

/*******************************************************************
*  Copyright(c) 2016 Chen Gonghao
*  All rights reserved.
*
*  chengonghao@yeah.net
*
*  文件内容:cghStl_algobase.h 中的copy的测试
******************************************************************/

#include "stdafx.h"
#include "cghVector.h"
#include "_cghList.h"
#include "cghDeque.h"
#include "cghStl_algobase.h"

class C
{
public:
	C() :_data(0){}
	C(int n) :_data(n){}

	int _data;
};

int _tmain(int argc, _TCHAR* argv[])
{
	using namespace::CGH;

	std::cout << "********************** 测试 copy 针对const char* 的特化版 *********************" << std::endl << std::endl;
	std::cout << "调用的版本:copy ( const char* )" << std::endl;
	const char srcChar[5] = {'a', 'b', 'c', 'd', 'e'};
	char destChar[5];
	CGH::copy(srcChar, srcChar + 5, destChar);
	for (int i = 0; i < 5; ++i)
	{
		std::cout << "srcChar[" << i << "] = " << srcChar[i] << "\t\t" << "destChar[" << i << "] = " << destChar[i] << std::endl ;
	}
	std::cout << std::endl;

	std::cout << "********************* 测试 copy 针对const wchar_t* 的特化版 ********************" << std::endl;
	std::cout << "调用的版本:copy ( const wchar_t* )" << std::endl;
	const wchar_t srcWchar[5] = {'a', 'b', 'c', 'd', 'e'};
	wchar_t destWchar[5];
	CGH::copy(srcWchar, srcWchar + 5, destWchar);
	for (int i = 0; i < 5; ++i)
	{
		std::cout << "srcWchar[" << i << "] = " << srcWchar[i] << "\t\t" << "destWchar[" << i << "] = " << destWchar[i] << std::endl ;
	}
	std::cout << std::endl;

	std::cout << "********************* 测试 int[] ***********************************************" << std::endl;
	std::cout << "依次调用:copy() --> copy_dispatch() --> _copy( input_iterator )" << std::endl;
	int arrSrc[5] = {0, 1, 2, 3, 4};
	int arrDest[5];
	CGH::copy(arrSrc, arrSrc + 5, arrDest);
	for (int i = 0; i < 5; ++i)
	{
		std::cout << "arrSrc[" << i << "] = " << arrSrc[i] << "\t\t" << "arrDest[" << i << "] = " << arrDest[i] << std::endl;
	}
	std::cout << std::endl;

	std::cout << "********************* 测试 deque<C> (C为自定义的类)***************************" << std::endl;
	std::cout << "依次调用:copy() --> copy_dispatch() --> _copy( random_access_iterator_tag )\n\t\t\t\t\t\t\t  --> _copy_d()" << std::endl;
	C cDequeElem[5];
	cghDeque<C> cSrcDeq;
	cDequeElem[0]._data = 100;
	cDequeElem[1]._data = 101;
	cDequeElem[2]._data = 102;
	cDequeElem[3]._data = 103;
	cDequeElem[4]._data = 104;
	cSrcDeq.push_back(cDequeElem[0]);
	cSrcDeq.push_back(cDequeElem[1]);
	cSrcDeq.push_back(cDequeElem[2]);
	cSrcDeq.push_back(cDequeElem[3]);
	cSrcDeq.push_back(cDequeElem[4]);
	cghDeque<C> cDestDeq(5, cDequeElem[0]);
	copy(cSrcDeq.begin(), cSrcDeq.end(), cDestDeq.begin());
	int m_cDeq = 0;
	for (cghDeque<C>::iterator it = cDestDeq.begin(); it != cDestDeq.end(); ++it)
	{
		std::cout << "cSrcDeq[" << m_cDeq << "] = " << it->_data << "\t\t" << "cSrcDeq[" << m_cDeq << "] = " << it->_data << std::endl;
		m_cDeq++;
	}
	std::cout << std::endl;

	std::cout << "********************* 测试 vector<int> *****************************************" << std::endl;
	std::cout << "依次调用:copy() --> copy_dispatch( T*, T* ) --> _copy( true_type )" << std::endl;
	cghVector<int> vecIntSrc;
	vecIntSrc.push_back(1);
	vecIntSrc.push_back(2);
	vecIntSrc.push_back(3);
	vecIntSrc.push_back(4);
	vecIntSrc.push_back(5);
	cghVector<int> vecIntDest(5);
	CGH::copy(vecIntSrc.begin(), vecIntSrc.end(), vecIntDest.begin());
	for (int i = 0; i < 5; ++i)
	{
		std::cout << "vecIntSrc[" << i << "] = " << vecIntSrc[i] << "\t\t" << "vecIntDest[" << i << "] = " << vecIntDest[i] << std::endl;
	}
	std::cout << std::endl;

	std::cout << "********************* 测试 vector<C> (C为自定义的类)**************************" << std::endl;
	std::cout << "依次调用:copy() --> copy_dispatch( T*, T* ) --> _copy_t( false_type )\n\t\t\t\t\t\t\t  --> _copy_d()" << std::endl;
	C cVecSrcElem[5];
	cVecSrcElem[0]._data = 0;
	cVecSrcElem[1]._data = 1;
	cVecSrcElem[2]._data = 2;
	cVecSrcElem[3]._data = 3;
	cVecSrcElem[4]._data = 4;
	cghVector<C> cVecSrc;
	cVecSrc.push_back(cVecSrcElem[0]);
	cVecSrc.push_back(cVecSrcElem[1]);
	cVecSrc.push_back(cVecSrcElem[2]);
	cVecSrc.push_back(cVecSrcElem[3]);
	cVecSrc.push_back(cVecSrcElem[4]);
	cghVector<C> cVecDest(5);
	copy(cVecSrc.begin(), cVecSrc.end(), cVecDest.begin());
	int m_cVec = 0;
	for (cghVector<C>::iterator it = cVecDest.begin(); it != cVecDest.end(); ++it)
	{
		std::cout << "cVecSrc[" << m_cVec << "] = " << it->_data << "\t\t" << "cVecDest[" << m_cVec << "] = " << it->_data << std::endl;
		m_cVec++;
	}
	std::cout << std::endl;

	system("pause");
	return 0;
}


 

结果如下图所示:

技术分享

STL简单 copy 算法的实现

标签:

原文地址:http://blog.csdn.net/chengonghao/article/details/51597745

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!