STL源碼剖析 數值算法 copy 算法

  • copy復制操作,其操作通過使用assignment operator 。針對使用trivial assignment operator的元素型別可以直接使用內存直接復制行為(使用C函數 memove或者memcpy)節約時間。
  • 還可以通過函數重載(function overloading)、型別特性(type traits)、偏特化(partial specialization)等技巧進一步強化效率。

  • copy函數將[first,last) 內的元素復制到區間[result,result+(last-first))內
  • 返回迭代器指向的是??result+(last-first)
  • 輸入區間使用?InputIterator,輸出區間使用?OutputIterator
  • 注意事項:1,result位于[first , last)之內的時候也就是輸出區間的起頭與輸入區間重疊,不能使用copy;如果輸出區間的尾端和輸入區間重疊,就可以使用

  • 上述第二種情況可能出現錯誤,是可能。如果輸出區間的起點位于輸入區間內部,copy算法可能會在輸入區間的(某些)元素尚未復制之前就將其覆蓋其值,導致錯誤
  • 如果copy算法根據其所接收的迭代器特性 決定使用memmove()來執行任務,就不會出現問題,因為memmove 會將整個輸入區間的內容復制下來就不會出現覆蓋的危險
#include <iostream>   //std::cout
#include <algorithm>  //std::fill
#include <vector>     //std::vector
#include <deque>template <class T>
struct display{void operator()(const T& value){std::cout << value <<' ';}
};int main(){{int ia[] = {0,1,2,3,4,5,6,7,8};//輸出區間的終點和輸入區間出現重疊 沒有問題std::copy(ia+2,ia+7,ia);std::for_each(ia,ia+9,display<int>()); //2 3 4 5 6 5 6 7 8std::cout << std::endl;}{int ia[] = {0,1,2,3,4,5,6,7,8};//輸出區間的起點和輸入區間出現重疊 可能會出現問題std::copy(ia+2,ia+7,ia+4);std::for_each(ia,ia+9,display<int>()); //0 1 2 3 2 3 4 5 6std::cout << std::endl;//本例結果正確 因為調用的copy算法使用memmove()執行實際復制操作}{int ia[] = {0,1,2,3,4,5,6,7,8};std::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first;  //advance(first,2)  2std::cout << * first << std::endl;----last;  //advance(last,-2) 7std::cout << * last << std::endl;std::deque<int>::iterator result = id.begin();std::cout << *result << std::endl; //0//輸出區間的終點和輸入區間重疊 沒有問題std::copy(first,last,result);std::for_each(id.begin(),id.end(),display<int>()); //2 3 4 5 6 5 6 7 8std::cout << std::endl;}{int ia[] = {0,1,2,3,4,5,6,7,8};std::deque<int>id(ia,ia+9);std::deque<int>::iterator first = id.begin();std::deque<int>::iterator last = id.end();++++first;  //advance(first,2)  2std::cout << * first << std::endl;----last;  //advance(last,-2)std::cout << * last << std::endl;std::deque<int>::iterator result = id.begin();std::advance(result,4);std::cout << *result << std::endl; //4//輸出區間的起點和輸入區間重疊 可能會出現問題std::copy(first,last,result);std::for_each(id.begin(),id.end(),display<int>()); //0 1 2 3 2 3 4 5 6//STL源碼剖析 此處會出現錯誤,原因在于copy算法不再使用memcove()執行實際的復制操作//但是實際沒有出現錯誤std::cout << std::endl;/*2 3 4 5 6 5 6 7 8 0 1 2 3 2 3 4 5 6 2702 3 4 5 6 5 6 7 8 2740 1 2 3 2 3 4 5 6 */}}
  • 使用vector代替上述的deque進行測試復制結果是正確的,因為vector的迭代器其實就是個原生指針
  • copy更改的是迭代器所指向的對象,并不是修改迭代器本身,他會為區間內的元素賦予新的數值,但不是產生新的元素,也不會改變迭代器的個數。即,copy不能用來將元素插入到空的容器中
  • 使用copy算法配合序列容器的insert_iterator?

?

#include <iostream>   //std::cout//完全泛化的版本
template <class InputIterator,class OutputIterator>
inline OutputIterator copy(InputIterator first,InputIterator last,OutputIterator result){return __copy_dispatch<InputIterator ,OutputIterator>()(first,last,result);
}//兩個重載函數 針對原生指針(視為一種特殊的迭代器)const char* 和 const wchar_t 進行內存的直接拷貝操作
//特殊版本1 重載形式 const char *
inline char* copy(const char* first,const char* last,char* result){std::memmove(result,first,last - first);return result + (last - first);
}//特殊版本2 重載形式 const wchar_t *
inline wchar_t* copy(const wchar_t* first,const wchar_t* last,wchar_t* result){std::memmove(result,first,sizeof(wchar_t)*(last - first));return result + (last - first);
}//copy泛化版本調用了一個 __copy_dispatch函數,這個函數有一個完全泛化版本和兩個偏特化版本
//完全泛化版本
//__copy_dispatch完全泛化版本根據迭代器的種類不同,調用了不同的__copy(),是因為不同種類的迭代器使用的循環條件不同,有快有慢
template <class InputIterator,class OutputIterator>
struct __copy_dispatch{OutputIterator operator()(InputIterator first,InputIterator last,OutputIterator result){return __copy(first,last,result,iterator_category(first));}
};//InputIterator 版本
template <class InputIterator,class OutputIterator>
inline OutputIterator __copy(InputIterator first,InputIterator last,OutputIterator result,std::input_iterator_tag){//通過迭代器的等同與否 決定循環是否繼續  速度很慢while(first!=last){*result = *first; //assignment operator++first;++result;}return result;
}//RandomAccessIterator 版本
template <class RandomAccessIterator,class OutputIterator>
inline OutputIterator __copy(RandomAccessIterator first,RandomAccessIterator last,OutputIterator result,std::random_access_iterator_tag){//劃分新的函數 為了讓其余地方可以使用return __copy_d(first,last,result, distance_type(first));
}template <class RandomAccessIterator,class OutputIterator,class Distance>
inline OutputIterator __copy_d(RandomAccessIterator first,RandomAccessIterator last,OutputIterator result,Distance*){//使用n決定循環的執行次數 速度快Distance n = last - first;while (n>0){*result = *first; //assignment operator++result;++first;n--;}return result;
}//偏特化版本1 兩個參數的型別都是T* 指針
template<class T>
struct __copy_dispatch<T*,T*>
{T* operator()(T* first,T* last,T* result){typedef typename __type_traits<T>::has_trival_assignment_operator t;return __copy_t(first,last,result,t());}
};//偏特化版本2 第一個參數是constT*指針形式 第二個參數是T* 指針形式
template<class T>
struct __copy_dispatch<const T*,T*>
{T* operator()(const T* first,const T* last,T* result){typedef typename __type_traits<T>::has_trival_assignment_operator t;return __copy_t(first,last,result,t());}
};//在上述偏特化版本指定參數類型為T*和const T*只針的前提下進一步探測 
//探測指針所指之物是否具備trivial assignment operator (平凡賦值操作符)
//SGI STL通過使用__type_traits<>編程技巧 和 增加一層間接性 來區分不同的 __copy_t()//適用于指針所指對象具備 trivial assignment operator 
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);
}//適用于指針所指對象具備 non-trivial assignment operator
template <class T>
inline T* __copy_t(const T* first,const T* last,T* result,__false_type){//原生指針是一種 RandomAccessIterator 所以交給 __copy_d()完成return __copy_d(first,last,result,(std::ptrdiff_t)0);
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446219.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446219.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446219.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python輸入數字成數組_python – Numpy:將數值插入數組的最快方法,使得數組按順序排列...

假設我有一個數組my_array和一個奇異值my_val. (請注意,my_array始終排序). my_array np.array([1, 2, 3, 4, 5]) my_val 1.5 因為my_val是1.5,我想把它放在1和2之間,給我數組[1,1.5,2,3,4,5]. 我的問題是&#xff1a;當my_array任意增大時,生成有序輸出數組的最快方式(即以微…

java 一維數組的反轉

代碼 public class ReverseArray {public static void main(String[] args) {String[] str {"AA", "BB", "CC", "DD"};System.out.println(Arrays.toString(str));reverse1(str);System.out.println(Arrays.toString(str));reverse2…

STL源碼剖析 數值算法 copy_backward 算法

copy_backward 時間技巧和copy類似主要是將[first&#xff0c;last)區間范圍內的元素按照逆行方向復制到以result-1為起點&#xff0c;方向同樣是逆行的區間上返回的迭代器的類型是result - (last - first)copy_backward支持的類型必須是BidirectionalIterators &#xff0c;才…

java線性查找和二分查找

線性查找 package lesson.l7_array;/*** Illustration** author DengQing* version 1.0* datetime 2022/6/23 14:19* function 線性查找*/ public class LineSearch {public static void main(String[] args) {String[]str{"AA","BB","CC"};boo…

python開發web項目_Django2:Web項目開發入門筆記(20)

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓 這一篇教程&#xff0c;我們一起來了解如何在CentOS系統中將Django2的Web項目部署到Nginx服務器。 CentOS系統雖然和Ubuntu系統都是Linux系統&#xff0c;但是環境搭建和部署過程還是有一些區別。 整個流程分為幾個部分&#xff1…

STL源碼剖析 Set相關算法 并集 set_union|交集 set_intersection|差集 set_difference |對稱差集 set_symmetric_difference

注意事項 四種相關算法&#xff1a;并集、交集、差集、對稱差集本章的四個算法要求元素不可以重復并且經過了排序底層接受STL的set/multiset容器作為輸入空間不接受底層為hash_set和hash_multiset兩種容器 并集 set_union s1 U s2考慮到s1 和 s2中每個元素都不唯一&#xff0…

python sqlserver 數據操作_python對Excel數據進行讀寫操作

python對Excel數據進行讀寫操作將學習到的基礎操作記錄在這里&#xff0c;便與復習查看1.python讀取Excel工作簿、工作表import xlrd # 讀取工作簿 wbxlrd.open_workbook(招生表.xls) # 讀取工作簿下所有的工作表 wswb.sheets() # 讀取工作簿下所有工作表名稱 wsnamewb.sheet_n…

Arrays數組工具類

介紹 代碼 package lesson.l8_arrays;import java.util.Arrays;/*** Illustration** author DengQing* version 1.0* datetime 2022/6/23 16:53* function Arrays數組工具類*/ public class ArraysUtil {public static void main(String[] args) {int[] arr1 new int[]{1, 12…

通過解析URL實現通過Wifi的用戶查找

使用鏈接 遇見數據倉庫|遇見工具|IP地址精確查詢|WIFI精確查詢|在線語音識別|夢幻藏寶閣估價|福利資源|自定義導航-met.redhttps://sina.lt/ 操作步驟 打開第一個鏈接&#xff0c;點擊高精度IP定位&#xff0c;然后點擊右上角&#xff0c;創建一個Key&#xff0c;隨便輸入一…

anaconda中怎么sh_【好工具】 深度學習煉丹,你怎么能少了這款工具!JupyterLab 遠程訪問指南...

歡迎來到【好工具】專欄&#xff0c;本次我們給介紹一款可以進行遠程深度學習煉丹的工具 JupyterLab 及其配置流程&#xff0c;幫助讀者在本地進行調試&#xff0c;Max 開發效率。作者 & 編輯 | Leong導言不知道讀者們有沒有發現&#xff0c;如果你用 Anaconda 中的 Notebo…

java 類和對象 屬性和行為 成員變量和局部變量

概念 使用 案例 public class PersonText {public static void main(String[] args) {Person person new Person();person.name "dq";person.age 11;person.eat("番茄炒蛋");} }class Person {/*** 姓名*/String name;/*** 年齡*/Integer age;/*** 方…

STL源碼剖析 數值算法 heap算法

算法 adjacent_findcountcount_iffindfind_iffind_endfor_eachgenerategenerate_nincludesmax_elementmergemin_elementpartitionremoveremoveremove_copyremove_ifremove_copy_ifreplacereplace_copyreplace_ifreplace_copy_ifreversereverse_copyrotaterotate_copysearchsea…

java 學生對象數組

題目 代碼 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 9:57* function*/ public class Student {int number;int state;int score;public static final int NUM 20;public static void main(String[] args) { // 對…

STL源碼剖析 lower_bound | upper_bound | binary_search

lower_bound 二分查找的一種版本&#xff0c;試圖在已經排序的區間內查找元素value&#xff0c;如果區間內存在和value數值相等的元素&#xff0c;便返回一個迭代器&#xff0c;指向其中的第一個元素。如果沒有數值相等的元素&#xff0c;會返回假設這個元素存在的前提下應該出…

java能調用python嗎_如何使用運行時在Java中調用python程序 - java

我想用來自Java的參數調用python程序。但是我的輸出是空白。代碼在這里。 Python代碼在這里&#xff1a; import sys print(sys.argv[1]) Java代碼在這里&#xff1a; public class PrintNumber{ public static void main(String[] args){ Process proc; try { proc Runtime.g…

java 匿名對象

概念 代碼 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 13:39* function 匿名對象*/ public class Anonymous {public static void main(String[] args) { // 用法1new Teacher().say("dq");new Teacher()…

STL源碼剖析 第七章 仿函數(函數對象)

函數對象&#xff1a;具有函數性質的對象使得用戶像使用函數一樣使用它一般函數提供兩個版本&#xff0c;第一個版本使用operator < ;第二版本需要用戶 指定某種操作第二版本就是設計一個函數&#xff0c;將函數指針作為算法的一個參數&#xff1b;或者將函數操作設計成為一…

開源合同管理系統_「物聯網架構」最適合物聯網的開源數據庫

物聯網產生大量的數據&#xff0c;包括流數據、時間序列數據、RFID數據、傳感數據等。要有效地管理這些數據&#xff0c;就需要使用數據庫。物聯網數據的本質需要一種不同類型的數據庫。以下是一些數據庫&#xff0c;當與物聯網一起使用時&#xff0c;會給出非常好的結果。物聯…

java 方法重載

概念 代碼 package lesson.l10_oop;/*** Illustration** author DengQing* version 1.0* datetime 2022/7/1 14:31* function 方法重載*/ public class Load {public static void main(String[] args) {Load load new Load();load.mOL(4);load.mOL(4, 5);load.mOL("ff&qu…

STL源碼剖析 第八章 配接器

設計模式&#xff1a;將一個類的接口轉化為另外一個類的接口 配接器的概觀和分類 改變仿函數接口 函數配接器 &#xff1b;queue和stack 通過修飾deque函數接口來實現改變容器接口 容器配接器 &#xff1b; insert、reverse、iostream 等iterators他們的接口可以由ite…