C++自修入門實境秀、C++ Primer 5版研讀秀 16/ ~3.3.Library vector Type圓滿-20190728_103302
3.3. Library vector Type A vector is a collection of objects, all of which have the same type. string的 collection是對字元char(characters)而言 vector的collection是對物件objects(veriables)而言 ⑧找對主詞 2:40 24:00 7:00古文、文言的能力程度,一試便知,一寫就詳 https://www.facebook.com/groups/393351767427366/permalink/2330431987052658/ 這些物件,都必須有同一個型別;就好像string裡也只有char這個型別一樣嚕! 所以這種集合是單一性質(同類、同類型)的集合 vector is a container容器 27:50 vector卻翻成「向量」,向量在中文之語境中並無「容器」之義,故此種翻譯是不當、失敗的,是外行的,是非中國人(指用中文的人)翻譯的。 翻成「向量」就像是機器翻譯一樣,全無人性 這都是中文程度差所造成的問題 30:00人類走向滅亡之因,同志婚合法,可否異性婚非法?同性戀可存活孳生其實只是因為攀附、寄生在異性社會而已。敢不敢異性戀不准結婚繁衍,只准同性戀來。我倒希望早早如此,如此的人類早早消滅才好。亂七八糟還理直氣壯。有種就支持到底,翻轉過來吧。就好像犯法免罪,不犯入罪好了。犯法的有人權,被犯的就小聲點好了。真是黃鐘毀棄,瓦釜雷鳴!我已絕子絕孫,我倒想看看您們還想有後代的,怎麼把這個人類社會恆久和平地維繫下去,反正我有幸、有命才能可看到結果了。但我應該不會這麼苦命長命吧。感恩感恩 南無阿彌陀佛 A vector is a class template . C++ has both class and function templates. 40:30 C++有類別和函式的模板(範本) 38:00 template 範本、模板 16章以前不會用到自訂模板 容器會在第二篇(部分)中深入討論 41:30 模板不是類別或函式本身,而可以視為是向編譯器仲介類別與函式的中間人,告訴編譯館要如何適當地產生出類別與函式 The process that the compiler uses to create classes or functions from templates is instantiation. 46:00從模板(範本)組建類別或函式的過程就叫46:30實例化(instantiation) 50:20 vector一定要包括一個型別不可省略角括弧<>4:59:00 頁97 55:20 53:30切記 vector也是個type,且是個library type(程式庫型別) vector is a template, not a type. Types generated from vector must include the element type, for example, vector<int>. 其實「vector<int>」就是一個型別,它這裡說vector不是型別的意思是說,不能單獨將vector寫成「vector」,而後沒有角括弧來指定它內中成員/元素的型別,這樣是不合法的。也就是說,只要用到vector這個模板,58:15就一定要配合用上<>角括弧來指定它內容物的型別,vector不能單獨使用,角括弧<>及其內容物的型別不能省略。 59:40因為參考不是物件,沒有實物,所以無法放在容器vector裡。 class types 1:1:00類別產生的型別;簡稱「類別型別」 1:3:40 模板型別(template type) 就像類別型別(class type)意思都是由模板/類別「產生」的型別 1:4:00舊版C++對一個內容物是vector本身或模板型別(template type)的vector的寫法是有點不同的:只是在最後一個結束的下角括弧前留個半形空格就是了。 1:14:07 3.3.1. Defining and Initializing vectors定義和初始化vectors 1:14:40 1:17:20 92頁中3.3表的cctype函式 第1個「c」 是「C++」的意思,以有別於其所承繼的「C」。第2個c,是character意思,就是判斷或操作一個character的相關函式。 ∴ ctype的意思就是有關character型別的函式 1:43:00 vector的預設初始化就是一個空的vector(an empty vector,沒有內容物元素的vector)。 1:46:10一個空的容器vector看似沒什麼用——瓠落無所容——,但其實馬上我們就會看到,我們可以在執行階段將元素加入至空的vector裡,這時空的vector就很有作用啦。像不像莊子對惠子說的: 今子有五石之瓠,何不慮以為大樽,而浮乎江湖;而憂其瓠落無所容,則夫子猶有蓬之心也夫! 1:56:00「何不慮以為」一些待加入vector容器的元素的皈依吶 1:58:15最長使用vector的方式就是先定義一個空的vector 2:8:52我學這個幹嘛?會去考證照嗎? 頁98 2:1:12 List Initializing a vector 串列初始化(list initialize)一個vector 2:17:40 串列初始化(list initialization)一定要用大括號,不能用圓括號: We cannot supply a list of initializers using parentheses: 2:18:30 因為圓括號就相當於cope(=),所以用圓括號來direct直接初始化,圓括號中只能有一個初始器的值 Creating a Specified Number of Elements 配置/建置指定數目的元素 2:22:50 Value Initialization (對於元素)值的初始化 頁99 表3.4 1:24:00 vector<T> v4 (n) v4 有一個 value-initialized 物件的 n 個拷貝。 unsigned n{5};//若無初始化,會造成內部錯誤 vector<string> v4(n); 1:31:35 value-initialized謂用預設初始化,如string即為""(空字串)。 1:38:10 allocator配置 vector<T> v5{a,b,c …… } v5有跟初始器同樣數目的元素;元素是由對應的初始器所初始化。 vector<unsigned> n{5,2,3,100,1,0}; - n { size=6 } std::vector<unsigned int,std::allocator<unsigned int> > + [allocator] allocator std::_Compressed_pair<std::allocator<unsigned int>,std::_Vector_val<std::_Simple_types<unsigned int> >,1> [0] 5 unsigned int [1] 2 unsigned int [2] 3 unsigned int [3] 100 unsigned int [4] 1 unsigned int [5] 0 unsigned int 2:37:00初始化的意義也取決於我們是用圓括號(小括號)還是花括號(大括號)來標記初始式 2:33:30 List Initializer or Element Count? 3:9:34 到底是一個串列初始化程序(器),還是一個vector大小vector元素多少的設定值 在中文語境應該是用「大小」或「多少」來翻這個count,而不是像機器翻譯或端著字典翻譯那樣翻成了「計數」。翻成「計數」,中文使用者誰聽得懂是啥碗糕。3:7:30 2:39:00 In a few cases, what initialization means depends upon whether we use curly braces or parentheses to pass the initializer(s). ⑦先抓動詞 depend才是真動詞,mean只是子句中的動詞 2:49:00圓括號 parentheses和大括號curly braces的使用在宣告、定義一個vector物件時是有舉足輕重的關鍵地位
Only if it is not possible to list initialize the object will the other ways to initialize the object be considered. ④倒序重組 2:56:30 will the other ways to initialize the object be considered.→ the other ways to initialize the object will be considered. 不見題目只見關鍵字「will、be」 On the other hand, if we use braces and there is no way to use the initializers to list 3:1:30 3:2:20 當我們用了大括號,而該型別卻不支援串列初始化(list initialization),那麼這樣的大括號,就會類似被轉換成小括號(圓括號),成了建構vector的大小的設定值3:22:00 3:25:00 in error (adj.) 頁100 只有在給定的值與元素型別相同時,才能可能用到串列初始化(list initialization) 練習3.12 vector<vector<int>> ivec;//OK,size=0 //vector<string> svec = ivec;//error,types of the elements are different between svec and ivec vector<string>svec(10, "null");//ok,size=10,elements are all "null" 練習3.13 3:33:00 vector<int> v1;//size=0 vector<int> v2(10);//size=10,elements are 0。 vector<int>v3(10, 42); //size=10,elements are 42; vector<int> v4{ 10 };//size=1,value is 10 vector<int> v5{ 10,42 };//list initialization :size=2,values are 10,42 respectively vector<string> v6{ 10 };//size=10,values are "".because 10 and string are different type. vector<string> v7{ 10,"hi" };//size=10,values are "hi". 3:46:10 3.3.2. Adding Elements to a vector 3:53:00 push_back 頁101 3:55:40 Key Concept: vector s Grow Efficiently 4:1:00 重要觀念、正確觀念 4:10:50 在C++中,最好是先定義一個空的vector,然後再在後來當知道每個元素的值時再將該元素加入到vector中,而不是一開始就像其他語言,如C或Java,定義好vector的大小(元素多少)。這樣反而才會更有效率,效能也較好。 除非是每個元素都需要被設定為同一個值時,才會去考慮先決定vector的size。 在9.4(頁355,vector的增長方式)時還會再詳述這樣做才能增加效能的緣故 4:14:00 Programming Implications of Adding Elements to a vector implications在此可翻成影響、副作用、附帶條件、(要付出的)代價、問題、課題 可變大小的vector不能用範圍for(range for述句來loop)4:25:50 總之,要注意不要讓loop 迴圈陷入無窮迴圈 一個range for的body,不能去改變這個range的大小 頁102 練習3.14 4:31:20 vector<int> v1; int i{0}; while (cin>>i) { v1.push_back(i); } for (auto v : v1) cout << v << endl; 練習3.15 vector<string> v1; string i{0}; while (cin>>i) { v1.push_back(i); } for (auto v : v1) cout << v << endl; 3.3.3. Other vector Operations 4:40:00 vector可以做的運算,大部分與string相同 4:42:55表3.5 vector的運算 4:50:40平方,自乘積,自相乘 5:0:35 size_type不是string專有的,vector也有 vector<type>::size_type 頁103 只有在vector元素型別支援的運算下,vector這個容器才能支援怎樣的運算。 Computing a vector Index 5:9:40 這裡compute不宜翻作計算,較近似中文的「數」,把它index『數』出來。5:18:50(數出、算出……都可以,就是不宜用「計」,用「計」算的話,在中文語境裡頭是好像要做加總或怎樣的計算似的,這對於索引值的性質而言,是不吻合的)這個「出」是不能省略的 計算 計算出 是不一樣的! 計算索引值時對索引值的計算5:23:00 計算出索引值,是藉由其他的運算算出了索引值是多少的意思 5:30:44 These grades can be represented by 11 clusters: 10 clusters of 10 grades each plus one cluster for the perfect score of 100. ①斷句 5:43:00 5:44:20「除、除以」的不同,2除3是(以)2除3的省略。所以「2除3」即「以2除3」「3除以2」→倒序重組。5:46:00自作自受,因果凜然。造口業的果報。 plus one cluster for the perfect score of 100 plus 是「加上」,不是「相加」的意思 one 代名詞,cluster for the perfect score of 100是說明one的補語。 10 clusters of 10 grades each 10個叢集,每一個each是10分 We can determine the cluster index for a given grade by dividing that grade by 10. 5:52:00 除 dividing 以 by 由這裡也可以知道 compute的意思是「算出」或「計算出」,而不是「計算」!5:57:00 要得到索引值這個結果,而不是用索引值去做計算 怎麼可以翻成「計算索引值」呢 Once we’ve computed the cluster index, we can use it to subscript our vector and fetch the counter we want to increment: 6:1:10 完成式,更可證明翻譯時不能漏掉「了」(結果了、結果完成了)或「出」(結果出來了) Once we’ve computed the cluster index, 翻譯 一旦我們計算出了叢集的索引值 「出了」二字若省略,則英文的時態也被消亡了!∴ 中文版翻此標題Computing a vector Index成了「計算一個vector的索引」是非常不當的!6:4:00這問題是出自譯者的中文差,未必是英文差。6:7:30 讀到這種標題,誰看得懂什麼意思?即使懂,能不是以為是要對索引做計算嗎? 6:17:00 頁104 bucket=cluster We start by defining a vector to hold the cluster counts. 我們一開始先定義一個vector來存放叢集的計數器。 中文版誤 → 我們一開始先定義一個vector來存放叢集的數量。6:32:30 Subscripting Does Not Add Elements 下標(subscript)只能更改元素,不能新增元素。要新增元素要用push_back成員函式 6:36:00 下標(subscript)的下當作動詞讀,似不錯。做下標記,或做出標記、把它(元素)標記出來的意思。 6:42:40 vector<int> ivec; for (decltype(ivec.size()) i = 0; i != 10; i++) { ivec.push_back(i); } 6:45:00 頁105 6:44:20 Subscript Only Elements that are Known to Exist! ⑦先抓動詞 subscript are ⑧找對主詞 Elements 只用下標(subscript)標出(擷取)確定存在的元素。 中文版:6:48:00 注意:下標運算只會擷取已知存在的元素! 「下標運算」是名詞、主詞,「擷取」是動詞 6:51:00 buffer overflow 緩衝區溢位 6:54:00 tip A good way to ensure that subscripts are in range is to avoid subscripting altogether by using a range for whenever possible. 確保下標有在範圍內的一個好辦法是盡可能使用範圍的for迴圈,完全避免下標運算。6:54:00 確保下標在範圍內的一種好方法是盡可能使用range for來完全避免下標。7:16:00 是要用(by)「using a range for」去全免於(to avoid……altogether)「subscripting」這件事。 中文版意不明,當改作: 確保下標有在範圍內的一個好辦法是盡可能使用範圍的for迴圈,而全然避免下標運算。7:20:10 意思就是只要能用(只要有可能whenever possible)range for的,就不要用下標來運算(即用「range for」來取代下標(subscript))。7:33:30就如我們在練習3.16所寫的程式碼,就是用range for,而不用下標(subscript)來存取每個元素
練習3.16 7:5:30 練習3.13 7:25:10 vector<int> v1;//size=0 vector<int> v2(10);//size=10,elements are 0。 vector<int>v3(10, 42); //size=10,elements are 42; vector<int> v4{ 10 };//size=1,value is 10 vector<int> v5{ 10,42 };//list initialization :size=2,values are 10,42 respectively vector<string> v6{ 10 };//size=10,values are "".because 10 and string are different type. vector<string> v7{ 10,"hi" };//size=10,values are "hi". vector<vector<int>> ivec{v1,v2,v3,v4,v5}; vector<vector<string>> svec{v6,v7}; for (vector<int> v : ivec) { cout << v.size() << "\t"; for (int v0 : v) cout << v0<<" "; cout<< endl; } for (vector<string> v : svec) { cout << v.size() << "\t"; for (string v0 : v) cout << v0 << " "; cout << endl; } 7:42:20黃色塊的部分都可以用auto來取代 練習3.17 7:49:33 vector<string> svec; string word{""}; while (cin>>word) { svec.push_back(word); } for (string &s : svec)//看看這裡的&可不可以省掉 for (char &c : s) c=toupper(c); unsigned i{1}; for (string s : svec) { cout << s<<" "; if (i == 8) { cout << endl; i = 0; } ++i; } cin: A good way to ensure that subscripts are in range is to avoid subscripting altogether by using a range for whenever possible. ^Z cout: A GOOD WAY TO ENSURE THAT SUBSCRIPTS ARE IN RANGE IS TO AVOID SUBSCRIPTING ALTOGETHER BY USING A RANGE FOR WHENEVER POSSIBLE. 練習3.18 8:5:12 vector<int> ivec; ivec[0] = 42; 果然完全是個災難! 8:9:30 vector<int> ivec{0}; ivec[0] = 42; 練習3.19 8:12:37 vector<unsigned> v1{42,42,42,42,42,42,42,42,42,42}; vector<unsigned> v2(10, 42); vector<unsigned>v3; for (size_t i = 0; i != 10; i++) { v3.push_back(42); } vector<vector<unsigned>> v{v1,v2,v3};// 8:24:00 int i{1}; for (vector<unsigned> v0 : v) { cout << "v"<<i<<":"<<v0.size() << ":"; ++i; for (unsigned vx : v0) cout << vx << " "; cout << endl; }//8:30:20 if (v1==v2) { if (v2==v3) { return 0; } } return -1; 練習3.20 8:38:00 vector<int> ivec; vector<int> isumvec; int i = 0; while (cin>>i) { ivec.push_back(i); } i = 1; int j=0; for (int isum:ivec ) { if(i/2!=1) j = isum; if (i/2==1) { isumvec.push_back(isum + j); i = 0; } ++i; } for (int isum : isumvec) cout << isum << " "; 改寫後: vector<int> ivec; vector<int> isumvec; int i = 0; while (cin>>i) { ivec.push_back(i); } i = 1; unsigned int j=0; j = ivec.size();//8:52:30 for (int x =0;x<j;++x) { if (j-x-1>=0 && x<j/2)//8:56:30 isumvec.push_back(ivec[x]+ivec[j-x-1]); } for (int isum : isumvec) cout << isum << " ";
留言