copy() 是一個調用頻率非常高的函數,所以SGI STL的copy算法用盡各種辦法,包括函數重載(function overloading)、型別特性(type traits)、偏特化(partial specialization) 編程技巧,無所不用其極地加強效率。下圖是整個copy()操作的脈絡。
copy算法將輸入區間[first, last)內的元素複製到result指向的輸出區間內,賦值操作是向前推進的。如果輸入區間和輸出區間重疊,複製順序需要多加討論。當result位於[first, last)之內時,也就是說,如果輸出區間的首部與輸入區間重疊,copy的結果可能不正確,建議選用copy_backward;如果輸出區間的尾部如輸入區間重疊,copy_backward的結果可能不正確,建議選用copy。當然,如果兩區間完全不重疊,copy和copy_backward都可以選用。
copy算法根據輸出迭代器的特性決定是否調用memmove()來執行任務,memmove()會先將整個輸入區間的內容複製下來,然後再複製到輸入區間。這種情況下,即使輸入區間和輸出區間有重疊時,copy的結果也是正確的。這也回答了上文中提調的,爲什麼result位於[first, last)之內時,copy的結果只是“可能不正確”。
copy爲輸出區間內的元素賦予新值,而不是產生新元素,它不能改變輸出區間的長度。換句話說,copy不能用來直接將元素插入到空容器中。如果你想要將元素插入序列之中,要麼使用序列容器的insert成員函數,要麼使用copy算法並搭配insert_iterator。
下面是copy算法唯三的對外接口,包括一個完全泛化版本和兩個重載函數:
- template <class InputIterator, class OutputIterator>
- inline OutputIterator
- copy(InputIterator first, InputIterator last, OutputIterator result) {
- return __copy_dispatch<InputIterator, OutputIterator>()(first, last, result);
- }
- inline char* copy(const char* first, const char* last, char* result) {
- memmove(result, first, last - first);
- return result + (last - first);
- }
- inline wchar_t* copy(const wchar_t* first, const wchar_t* last, wchar_t* result) {
- memmove(result, first, last - first);
- return result + (last - first);
- }
copy()函數的泛化版本中調用了一個__copy_dispatch()的仿函數(老方法了^_^),此仿函數有一個完全泛化版本和兩個偏特化版本:
- template <class InputIterator, class OutputIterator>
- struct __copy_dispatch {
- OutputIterator operator(){InputIterator first, InputIterator last,
- OutputIterator result) {
- return __copy(first, last, result, iterator_category(first);
- } ;
- /*
- * __copy_dispatch()的完全泛化版本根據迭代器種類的不同,調用
- * 不同的__copy(),爲的是不同的迭代器使用的循環條件不同,有快
- * 慢之別
- */
- template <class InputIterator, class OutputIterator>
- inline OutputIterator __copy(InputIterator first, InputIterator last,
- OutputIterator result, input_iterator_tag) {
- for( ; first != last; ++first, ++result)
- *result = *first;
- return result;
- }
- template <class RandomAccessIterator, class OutputIterator>
- inline OutputIterator __copy(RandomAccessIterator first, RandomAccessIterator last,
- OutputIterator result, random_access_iterator_tag) {
- __return __copy_d(first, last, result, distance_typ(first));
- }
- 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;
- }
- template <class T>
- struct __copy_dispatch<T*, T*> {
- T* operator()(T* first, T* last, T* result) {
- typedef typename __type_traits<T>::has_trivial_assignment_operator t;
- return __copy_t(first, last, result, t());
- };
- template <class T>
- struct __copy_dispatch<const T*, T*> {
- T* operator()(T* first, T* last, T* result) {
- typedef typename __type_traits<T>::has_trivial_asssignment_operator t;
- return __copy_t(first, last, result, t());
- };
- /*
- * 這兩個偏特化版本是在“參數爲原生指針形式”的前提下,利用
- * __type_traits<>編程技巧來探測指針所指向之物是否有
- * trivial assignment operator. 如果指針所指對象擁有
- * trivial assignment operator,則可以通過memmove()進行復制,速度要比
- * 利用賦值操作賦快許多
- */
- template <class T>
- inline T* __copy_t(const T* first, const T* last, T* result, __true_type) {
- memmove(result, first, sizeof(T) *(last - first);
- return result + (last - first);
- }
- 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);
- }
以上就是copy()的故事,一個無所不用其極強化效率的故事。
copy_backward()的實現與copy()極爲相似,不同是它將[first, last)區間內的每一個元素,以逆行的方向複製到,以result-1爲起點,方向同樣爲逆行的區間上。