stl的一些注意地方

容器是用來存儲和組織其他對象的對象

頭文件內容
vector表示一個必要時可自動增加容量的數組
array數組容器優於vector<>的一個優點是,它可以完全在棧上分配,而vector<>總是需要訪問堆
deque增加了向容器開頭添加元素的能力
forward_list單向鏈表,以前向方式處理鏈表中的元素,就比List快
mapmap<K,T>是關聯容器,用關聯鍵(類型爲k)存儲T類型的每個元素
unordered_map類似於map但是該容器中的鍵/對象對沒有特定的順序
set是一個映射,各對象作爲自身的鍵,所有對象必須唯一,並且無法在集合中修改對象
unordered_set類似於set,但元素進行無序排列
bitset定義表示固定位數的bitset<T>類模板,通常用來存儲表示一組狀態或條件的標誌

大多數STL容器都會自動增大其容量來容納所存儲的元素。這些容器的附加內存用一個名爲分配器的對象來提供,分配器一般會在需要時分配堆上的內存,也可以通過一個額外的類型形參,提供自己的分配器類型。

例如,創建向量的vector<T>模板實際上是一個vector<T,A<T>>模板,第二個類型的形參默認分配器類型是allocator<T>

容器適配器是包裝了現有STL容器類的模板類,如隊列,棧

迭代器對象的行爲和指針相似,它對於訪問除容器適配器定義內容之外所有STL容器的內容非常重要,容器適配器不支持迭代器

得到的迭代器類型取決於使用的容器的種類

智能指針用於動態分配內存對象

unique_ptr<T>類型定義了一個對象,用來存儲唯一對象的指針

shared_ptr<T>類型指針可以同時有多個shared_ptr對象指向相同的對象,並且引用該對象的shared_ptr對象數量會記錄下來,指向同一個對象的所有shared_ptr對象必須在他們所指向的對象刪除之前刪除,當最後一個指向給定對象的shared_ptr對象刪除後,它指向的對象才能刪除且釋放其內存

weak_ptr<T>類型存儲了一個連接到shared_ptr的指針,weak_ptr<T>不會遞增或遞減所鏈接shared_ptr的引用數,所以可以在引用它的最後一個shared_ptr刪除之前,不會刪除對象,釋放其內存。weak_ptr對象就是爲避免引用循環問題而設計的,使用weak_ptr對象指向一個shard_ptr對象所指向的對象,就可以避免引用循環。只需要刪除shared_ptr對象,它指向的對象就能刪除,接着與shared_ptr相關的weak_ptr對象就變爲無效。

make_unique<T>()函數模板在堆上創建了一個新的T對象,在創建一個指向T對象的unique_ptr<T>對象如:

auto pBox=std::make_unique<CBox>(2.0,3.0,4.0);

同理,最好使用make_shared<T>()函數在堆上創建一個T類型的對象,再返回一個指向它的shared_ptr<T>對象,因爲內存分配更加高效。

有時需要訪問智能指針包含的指針:這稱爲裸指針,調用智能指針對象的get()成員會返回裸指針,調用reset()會把裸指針重置空

對智能指針的轉化需要使用static_pointer_cast,dynameic_pointer_cast和const_pointer_cast,在memory頭文件中定義。

算法在algorithm和numeric頭文件中定義。

函數適配器是允許合併函數對象以產生一個更復雜的函數對象的函數模板

vector的函數:capacity()返回當前容量,max_size()返回矢量中元素的最大可能數目。resize()可以增加或減小矢量大小,front()返回第一個元素,back()返回最後一個元素,pop_back()刪除最後一個元素,clear()刪除所有元素,insert()插入新元素,emplace()和emplace_back用於在矢量中插入對象時就地創建它,erase()可以刪除矢量中任何位置的一個或多個元素。assign用另一序列替換一個矢量中的全部內容,或者用給定數量的對象實例替換矢量內容。

functional頭文件定義比較謂詞的完整函數對象集合,包括:less<T> less_equal<T> equal<T> greater_equal<T> greater<T>,用作sort函數的第三個參數

數組容器的表達方式

template<class T,size_t N>
void listValues(const array<T,N>& data)
{
  ..
}

使用numeric頭文件定義的accumulate()模板函數可以求數組之和,第一個參數爲開始位置,第二結束位置,第三個相加後賦予的值。

雙端隊列的前段添加元素的函數爲push_front(),刪除第一個元素爲pop_front

列表的begin()和end()函數返回的是迭代器是雙向迭代器,只能使用遞增或遞減運算符修改雙向迭代器的值。

列表函數advance()函數來遞增迭代器,將第一個實參指定的迭代器遞增第二個實參指定的次數。emplace()在迭代器指定的 上構建一個元素,emplace_front()在列表開頭構建一個元素,emplace_back()在列表結尾構建一個元素。remove()函數從列表中刪除匹配特定值的元素。unique()函數將消除列表中相鄰的重複元素,如果先排序,即可確保所有元素的唯一。splice()函數可以刪除一個列表的全部或一部分,並將它插到另一個列表中,第一個實參爲迭代器,指定插入元素的位置,第二個是插入的元素來自的列表,將會刪除原來的位置的元素。merge()函數刪除作爲一個實參提供的列表中的元素,並將它們插入調用該函數的列表中,在調用之前,2個列表都必須適當地排序。例如:

list<int> numbers{1,2,3};//1 2 3
list<int> values{2,3,4,5,6,7,8};//2 3 4 5 6 7 8
numbers.merge(values);//1 2 2 3 3 4 5 6 7 8

remove_if()函數基於應用一元謂詞的結果來刪除列表中的元素。一元謂詞是一個應用到單個實參的函數對象,它返回一個bool值true或false,如果向一個元素應用謂詞的結果是true,就會從列表刪除該元素。通常我們會定義自己的謂詞。基類模板如下:

template<class _Arg,class _Result>
struct unary_function
{
  typedef _Arg argument_type;
  typedef _Result result_type;
};

template<class T>class is_negative:public std::unary_function<T,bool>
{
   public:
    result_type operator()(argument_type& value)
{
  return value<0;
 }
};

forward_list,每個元素都包含指向下一個元素的指針,只能向前遍歷元素。before_begin()函數返回一個迭代器,指向第一個元素前面的位置,distance()返回元素個數。forward_list<T>容器提供的性能比List<t>容器好得多,只有一個鏈接要維護,使其操作起來更快,且不需要跟蹤元素的個數。

priority_queue<t>容器是一個隊列,它的頂部總是具有最大或最高優先級的元素,不過優先級隊列不能訪問隊列後端的元素,只能訪問前端的元素。

tuple<>類模板定義在tuple頭文件中國,此模板對於array<>容器是一個有用的輔助,tuple<>對象封裝了很多不同的項,這些項可以具有不同的類型。例子如下:

using Record=std::tuple<int,std::string,std::string,int>

std::array<Record,5>personal{Record{1001,"joan","jetson",35},
Record{1002,"jim","jones",26},
Record{1003,"june","jello",31},
Record{1004,"jack","jester",39}};

要訪問元祖中的字段,需要使用get()模板函數,注意get()函數模板的類型形參必須是一個編譯時常量。

關聯容器(如map<K,T>)最重要的特性是無須搜索就可以檢索特定的對象,關聯容器內T類型對象的位置由於對象一起提供的類型爲K的鍵確定,因此只要提供適當的鍵,就可以快速地檢索任何對象。當創建map<K,T>容器時,K是鍵的類型,用於存儲T類型的關聯對象,鍵/對象對會存儲爲pair<K,T>類型的對象,pair<K,T>在utility頭文件中定義。可以通過成員first和second訪問一個對中的元素。.first爲鍵,.second爲對象。insert()函數返回的值也是一個對,對中第一個對象是迭代器,第二個對象是bool類型值,成功爲true,失敗爲false;

iterator頭文件定義流迭代器的幾個模板,用於將數據從源傳到目的地,流迭代器作爲指向輸入流或輸出流的指針,可以在流和任何使用迭代器的源或目的地之間傳輸數據,如算法。

std::istream_iterator<int> numbersInput{std::cin};//創建輸入流迭代器

sstream頭文件定義了basic_istringstream<T>模板,這個模板定義了可以訪問流緩衝區中的數據對象類型。

std::string data{"2.4 2.5 3.6 2.1 6.7 6.8 94 95 1.1 1.4 32"};
std::istringstream input{data};
std::istream_iterator<double>begin (input),end;//由於從string對象data中創建istringstream對象,因爲可以像流一樣從data中讀取數據。

copy函數將迭代之間指定的實參複製到輸出流迭代器中。如:

std::ostream_iterator<int> out{std::cout};
int data[]{1,2,3,4,5,6,7,8,9};
std::copy(std::cbegin(data),std::cend(data),out);

not2<>()模板函數,它創建一個二元謂詞,它是傳遞爲實參的函數對象定義的二元謂詞的負值。例如,not2(less<int>())創建一個二元謂詞來比較Int類型的對象,如果左操作數不小於右操作數,則返回true。

函數對象模板說明
plus<T>計算兩個T類型元素的和
minus<T>通過從第一個操作數中減去第二個操作數來計算他們之間的差
Multiplies<T>計算兩個T類型元素的積
divides<T>用第一個T類型操作數除以第二個T類型操作數
modulus<T>計算第一個操作數除以第二個操作數後的餘數
negate<T>返回T類型操作數的負值
上述的這些都是通過transform來使用的

transform的這個版本將一元函數f應用到迭代器begin,end指定的範圍中的所有元素,並從迭代器result指定的位置開始存儲結果

OutputIterator transform(InputIterator begin,InputIterator end,
OutputIterator result,UnaryFunction f)

由begin1和end1指定的範圍表示最後一個實參指定的二元函數f的左操作數集合表示右操作數的範圍從begin2迭代器指定的位置開始,這個範圍不需要提供end迭代器,因爲這個範圍的元素數量必須與begin1和end1指定的範圍中的元素個數相同,結果將從resut迭代器位置開始存儲在這個範圍內,如果希望結果存儲回該範圍中,result迭代器可以與begin1相同,但是它一定不能是begin1和end1之間的其他任何位置。

transform(InputIterator1,begin1,InputIterator end1,InputIterator2 begin2,OutputIterator result,BinaryFunction f)

靜態斷言可以在編譯期間檢測用法錯誤,形式如下:

static_assert(constant_expression,string_literal);

constant_expression,應的到一個可轉換爲bool類型的值,如果結果是true,就什麼都不做,如果它是false,編譯器就顯示字符

λ表達式定義一個沒有名稱,也不需要顯式類定義的函數對象,λ表達式作爲一種手段,用來將函數作爲實參傳遞到另一個函數。λ形參有幾個限制,不能指定λ表達式形參的默認值,形參列表的長度不能變,默認返回類型會返回值的類型,也可指定如:

[](double x)->double{return x*x*x;}

f方括號之間是=,則λ主體可以按值訪問封閉作用域中的所有自動變量,即變量值可用在λ,但不會修改原始的變量,如果是&引用,則可以訪問加修改。按值訪問中,想修改外面的變量需要加上mutable。

可以將無狀態的λ賦予函數指針變量,這樣就給λ表達式指定了名稱,如

auto sum=[](int a,int b){return a+b;};
cout<<sum(5,10);//直接調用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章