小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

[譯]2010新版STL修訂內(nèi)容(VC2010) | ColinOrg

 kimbaku 2011-01-11

揭示STL重要更改

預(yù)備知識:

l 理解標準C++ 0x 的concepts,例如:auto 關(guān)鍵字,lambda 表達式、右值引用等。

l 熟練使用STL。熟悉2個及以上STL容器的使用。

l 你手上必須有有VC2010的編譯器,或者其它支持最新的C++標準和更新Stl的編譯器。

這篇文章介紹了新版STL修訂內(nèi)容。這些變化是TR1中最為關(guān)注的內(nèi)容(譯注1);以下是STL的新增特性:

l Constant迭代器

l array類

l tuple類

l <algorithm>中新增函數(shù)

l 隨機生成器類(<random>)

l 對sets及無序sets容器的改進

l 對maps及無序maps的改進

l 正則表達式

l 功能的改進及實用的頭文件

l 加強指針管理類

Constant 迭代器

首先說明,constant迭代器并不等于const迭代器。constant迭代器是const_iterator。 將const關(guān)鍵字加在 iterator前時,其所指的變量是無法修改的。而const_iterator則在首次賦值后不再可指向其它變量(類似:常量指針和指向常量的指針)看了下面代碼后,你應(yīng)該會有一個清晰的認識:

using namespace std;
vector<int> IntVector;
...
// Normal iterator
vector<int>::iterator iter_nc = IntVector.begin();
*iter_nc = 100; // Valid
iter_nc = IntVector.end(); // Valid
// Constant Iterator
vector<int>::const_iterator iter_c = IntVector.begin();
*iter_c = 100; // INVALID!
iter_c = IntVector.end(); // Valid
// The 'const' iterator
const vector<int>::iterator iter_const = IntVector.begin();
*iter_const = 100; // Valid
iter_const = IntVector.end(); // Invalid (Why? Learn C++!)
// The 'const' Constant Iterator
const vector<int>::const_iterator iter_const_c = IntVector.begin();
*iter_const_c = 100; // Invalid!
iter_const_c = IntVector.end(); // Invalid

新特性

容器中新增函數(shù)可以明確返回Constant迭代器。在此之前,我們先了解一下迭代器返回規(guī)則:

1. 如果容器是constant,或者類方法前申明const,則將返回const_iterator。

2. 如果左值是const_iterator,普通的iterator將被返回,但會向下轉(zhuǎn)型為const_iterator;

3. 其它情況,將返回普通iterator;

注:大多數(shù)迭代器訪問方法(eg:begin,end)有相應(yīng)的重載版本以返回constant 或non-const迭代器 ;

因此,你可明確指明返回的是constant還是普通迭代器;

以下為新增方法:

訪問方法

含義

cbegin

返回容器第一個元素的const_iterator .

cend

返回容器最后一個元素后一位的 const_iterator .

crbegin

返回rbegin 的 const_iterator 。即最后一個元素的constant迭代器.

crend

返回rend的 const_iterator 。即第一個元素前一位的constant迭代器.

以上所有方法都在相應(yīng)的容器類中申明為const。

為什么要引入這些方法?

你當然可以指定你需要那種迭代器,可能你根本就不需要這些新的方法;

加入這些方法的主要原因是因為新修訂的auto關(guān)鍵詞的引入;如果你已經(jīng)了解auto關(guān)鍵詞的含義,你應(yīng)該知道我們可以在變量申明時不用明確指定類型。編譯器會根據(jù)表達式的右值推導(dǎo)變量類型;當有如下調(diào)用:

auto iter = IntVector.begin();

可以指定是普通還是constant迭代器被返回。因此,為了返回一個constant迭代器(const_iterator),你可以使用:

auto iter = IntVector.cbegin(); // cbegin
// The return type is: vector<int>::const_iterator

這樣,這個迭代器以只讀模式遍歷vector,可以寫出如下代碼:

for(auto iter = IntVector.cbegin(); iter != IntVector.cend(); ++iter) { }

需要說明的是,constant迭代器可以訪問 非const成員方法(我不敢保證,我只是在源碼中看到)。因此,最好使用cend來代替end檢查有效性。

在sets和maps集合中又是如何?

對于所有的集合類(set,multiset, unordered_set, and unordered_multiset),其迭代器總是constant的。也就是說,當調(diào)用方法begin/end,find 以及下標操作符[],都是返回的constant 迭代器。像begin,find這些方法,雖然它們返回的數(shù)據(jù)類型都是非constant迭代器,但其行為是constant迭代器。

看以下代碼:

set<int> is;
is.insert(10);
*is.begin() = 120;
wcout << is.count(10) << ", " << is.count(120);

以上例子首先插入10到set中,然后試圖修改第一個元素的值。

因為只有一個元素插入進來,begin將返回指向該元素的迭代器;在vc9及之前的編譯器中,可成功修改值為120;

但從vc10開始,第三行將不能編譯通過,編譯器報錯為:

error C3892: ’std::**::begin’ : you cannot assign to a variable that is const

對于map,鍵不可修改,值可修改。以下是代碼示例:

map<int, int> imap;
imap.insert( make_pair( 1, 1028 ));
imap.insert( make_pair( 2, 2048 ));
imap.find(1)->second = 1024; // Compiles
imap.find(2)->first = 4; // Error
imap[2] = 2000;
*imap.begin()->first = 10; // Error
*imap.begin()->second= 10; // Compiles
*imap.cbegin()->second= 10;
// Error on VC10, since iterator is constant. NA for VC9 

數(shù)組類array

array類是STL新增容器類,用于在存儲一個固定大小的數(shù)組。數(shù)組大小與數(shù)據(jù)元素類型一同由模版參數(shù)指出。其指定的大小數(shù)值必須是一個常量運行時的(與其它C/c++數(shù)組一樣)。不像其它容器能夠增加或減少容器大小,array支持其它標準方法-如迭代,隨機訪問,交換數(shù)據(jù),賦值等。

頭文件:<array>

命名空間:tr1.但由于’using tr1::array’ 已被頭文件包含。所有,在使用中,申明std就可以了。

示例:

array<int, 64> IntArray;

第一個參數(shù)指定模版數(shù)據(jù)類型,第二個是一個常量編譯時的整型。定義之后,IntArray的大小不能再改變。當然,除了int,可以使用其它的基本數(shù)據(jù)類型。如果要使用自定義類,則要實現(xiàn)復(fù)制構(gòu)造函數(shù),重載賦值操作符,比較操作符。同時,默認構(gòu)造函數(shù)必須為公有。

這個類的引入是為了和其它STL容器進行無縫整合。例如,你使用vector或list,需要調(diào)用begin/end方法來訪問元素。當你想將其作為普通數(shù)組使用時,代碼會編譯失敗。這必須改變。用array類,你可以同時獲得STL的靈活性和普通數(shù)據(jù)的性能。

依據(jù)最近的編譯器報告(tr1 增刊),可以使用以下方式來初始化array:

array<int, 64> IntArray;

如果忽略1個或多個元素沒賦值,它們將被置為0.

如果對array沒有做任何初始化操作,其所有元素處于未初始化狀態(tài)。

array類支持以下STL標準方法:

l at, operator [] – 返回指定位置元素引用.

l back, front – 各自返回第一及最后一個元素位置引用;

l begin, cbegin, rbegin, crbegin -返回第一個元素迭代器;

l end, cend, rend, crend – 返回最后一個元素后一位的迭代器;

l empty – 判斷容器是否為空。僅當數(shù)組大小為0時返回true;

l size, max_size – 返回array對象大小,該大小在編譯期間確定;

以下方法需要重點說明:

array::assignarray:fill

這2個方法功能相同,實現(xiàn)將array所有元素賦值為一個給定值。此方法也可用來通過指定值替換array對象的所有元素。例如:

array<int,10> MyArray;
MyArray.fill(40); // or 'assign'
for_each(MyArray.cbegin(), MyArray.cend(),
[](int n) { std::wcout << n << "\t";} ); 

將10個元素賦值為40,之后輸出到控制臺。

array::data

此方法返回數(shù)組第一個元素地址。與普通數(shù)組相比(eg:int_array[N]),此方法類似于表達式&int_array[0] 或者int_array。 此方法是由指針直接操作。const及非const方法都可用。例如:

int* pArray = MyArray.data();
// Or
auto pArray = MyArray.data(); 

array::swap(array&) 和swap(array&, array&)

交換兩個數(shù)組大小和類型相同的array對象。第一個方法是非靜態(tài)方法,實現(xiàn)將本數(shù)組內(nèi)容與參數(shù)中的指定數(shù)組交換。第二個方法,攜帶2個array&參數(shù),互換內(nèi)容。例如:

typedef array<int,10> MyArrayType;
MyArrayType Array1 = {1,2,4,8,16};
MyArrayType Array2;
Array2.assign(64);
Array1.swap(Array2);
// Or - swap(Array1, Array2);
// Array1 - 64, 64...64
// Array2 - 1,2,4,....0 

如果試圖交換不同類型數(shù)組,編譯器會報錯:

array<int,5> IntArrayOf5 = {1,2,3,4,5};
array<int,4> IntArrayOf4 = {10,20,40};
array<float,4> FloatArrayOf4;
IntArrayOf5.swap(IntArrayOf4); // ERROR!
swap(IntArrayOf4, FloatArrayOf4); // ERROR! 

六種比較操作符

作為全局函數(shù)的==, !=, <, >, <=, 及>=可用來比較2個相同類型的數(shù)組對象:

typedef array<int,10> MyArrayType;
MyArrayType Array1 = {1,2,4,8,16};
MyArrayType Array2;
Array2.assign(64);
if (Array2 == Array1)
wcout << "Same";
else
wcout << "Not Same"; 

結(jié)果輸出"Not Same" .

元組類tuple

STL程序員都知道pair 結(jié)構(gòu),它用來包裝2個任意類型的元素。除了maps,在其它地方這個結(jié)構(gòu)也非常有用,我們可以用來包裝2個元素,而不用定義一個結(jié)構(gòu)體。我們可通過first、 second變量取得這2個元素的值。

pair<string,int> NameAndAge;
NameAndAge.first = "Intel";
NameAndAge.second = 40; 

程序員經(jīng)常typedef 它們,這樣變量就可以容易的申明并可將pair 傳給函數(shù)。

但是,如果你需要保證多于2個的元素,該怎么做呢?

通常,你會定義一個結(jié)構(gòu)體,或使用多重pair。這樣的格式并不能與STL無縫整合。

tuple 類就是為此而生。這個類允許將2至10個元素包裝在一起。

所有元素類型都可不同,如果要加入自定義,其依賴的操作必須事先定義。tuple類通過模版重載具體如何工作,已超出我的理解,這里我只說明它可以完成什么,以及我們可以在哪里使用。

l 頭文件: <tuple>

l 命名空間: tr1. ‘using tr1::tuple’ 已包含在 std .

申明2個元素元組:

tuple<int,int> TwoElements;

在構(gòu)造函數(shù)中初始化:

tuple<int,int> TwoElement (400, 800);

如果初始化,則必須初始化所有元素,以下方式報錯:

tuple<int,int> TwoElement (400); // Second initializer missing

這個錯誤可能不那么明顯,但是你應(yīng)該明白這個原則:必須初始化所有成員。

構(gòu)造之后的初始化并不簡單。在pair中,有make_pair 來輔助pair的初始化。自然的,tuple也有相應(yīng)的輔助函數(shù)make_tuple。如果你已經(jīng)讀過或?qū)⒁xVC2010并行編程,你會發(fā)現(xiàn)C++庫中類似的完成類似的功能有其它新的make_函數(shù)。(譯注2:并行編程地址)

下面例子說明如何初始化tuple對象:

TwoElement = make_tuple(400, 800); 

跟tuple模版類一樣,make_tuple 有傳入2至10個參數(shù)的重載函數(shù)版本。make_tuple充分利用C++0x中右值引用的思想,完美的支持STL新特性。它允許復(fù)用同一對象而不是調(diào)用復(fù)制構(gòu)造函數(shù)和賦值操作,以此提升整體性能。

我們可以結(jié)合make_tuple和auto關(guān)鍵詞來靈活的定義一個tuple:

auto Elements = make_tuple(20, 'X', 3.14159);
// Eq: tuple<int, char, double> Elements(20, 'X', 3.14159); 

如何訪問tuple中的元素?

對于pair對象,我們都是簡單的使用其內(nèi)部定義的變量first/second來訪問元素。但是tuple類中并沒有定義這樣的變量,我們需要通過輔助函數(shù)get來訪問這些未命名變量。例如:

tuple<string, int, char> NameAgeGender("Gandhi", 52, 'M');
int nAge = get<1>(NameAgeGender); 

get<index>()中的可用索引必須在對象初始化的元素范圍之內(nèi)。索引以0為起點。在上述例子中,索引范圍為[0,2],get<1>用于訪問NameAgeGender對象中的第二個元素,返回一個整型給nAge。

get函數(shù)的索引必須是一個常量編譯時的整型并在有效范圍內(nèi)。返回類型的推導(dǎo)也是常量時;以下代碼編譯器會報錯:

int nAge = get<0>(NameAgeGender);
// ERROR - cannot convert from 'string' to 'int' 

這樣也有助與發(fā)現(xiàn)潛在的代碼缺陷:

char cGender = get<1>(NameAgeGender); // Leve 4 C4244 warning - 'int' to 'char'
// Should be get<2> 

更重要的是,get可以賦值給auto關(guān)鍵詞:

auto sName = get<0>(NameAgeGender); // Type deduction - 'string' 

對于非const類型tuple對象,返回類型為元組元素的引用,這樣,可以修改元素值:

// Modify Age
get<1>(NameAgeGender) = 79; 

也可以將這個返回類型放在另一個引用中,并在之后修改。使用auto關(guān)鍵詞也可行:

auto & rnAge = get<1>(NameAgeGender) ;
rnAge = 79 

需要指出的是,get函數(shù)同樣適用于array類:

array<char, 5> Vowels = {'A','E','I','o','U'};
char c = get<1>(Vowels); // 'E'
get<3>(Vowels) = 'O'; // Modify
get<10><Vowels); // ERROR - Out of range! 

tie函數(shù)

這個函數(shù)實現(xiàn)make_tuple函數(shù)的逆操作。使用這個函數(shù),你可以用一個tuple對象來初始化一組變量。看例子:

tuple<string, int, char> NameAgeGender("Gandhi", 52, 'M');
string sName;
int nAge;
char cSex;
tie(sName, nAge, cSex) = NameAgeGender; 

以上代碼將這3個變量對應(yīng)的設(shè)置為值 "Gandhi", 52, and ‘M’。我想tie是否可以用于取代make_tuple?結(jié)果證明不行:

tuple<string, int, char> NameAgeGender;
NameAgeGender = tie("Gates", 46, 'M'); // make_tuple
string sName; int nAge; char cSex;
make_tuple(sName, nAge, cSex) = NameAgeGender; // NO error. See below. 

tie函數(shù)返回tuple對象的引用;make_tuple則是創(chuàng)建一個對象,返回的并非引用。上面最后一行試圖修改一個臨時創(chuàng)建的tuple對象,編譯器不報錯,卻并不能得到正確結(jié)果。因此,最好還是按照它們設(shè)計的功能來使用這2個函數(shù)。

六種關(guān)系操作符

與array類一樣,tuple類中同樣實現(xiàn)了6種操作符的功能。所有的重載版本都要求作關(guān)系操作的兩個tuple對象必須是同類型的(所包含的元素的對應(yīng)位置的類型必須相同)。

(未完待續(xù))

【注1】TR1:

C++ Technical Report 1 (TR1)是ISO/IEC TR 19768, C++ Library Extensions(函式庫擴充)的一般名稱。TR1是一份文件,內(nèi)容提出了對C++標準函式庫的追加項目。這些追加項目包括了正則表達式、智能指針、哈希表、隨機數(shù)生成器等。TR1自己并非標準,他是一份草稿文件。然而他所提出的項目很有可能成為下次的官方標準。這份文件的目標在于「為擴充的C++標準函式庫建立更為廣泛的現(xiàn)成實作品」。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多