久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

STL學(xué)習(xí)小結(jié)

 fisher60 2012-08-01
STL就是Standard Template Library,,標(biāo)準(zhǔn)模板庫(kù)。這可能是一個(gè)歷史上最令人興奮的工具的最無(wú)聊的術(shù)語(yǔ),。從根本上說(shuō),,STL是一些“容器”的集合,這些“容器”有list, vector,set,map等,,STL也是算法和其它一些組件的集合,。這里的“容器”和算法的集合指的是世界上很多聰明人很多年的杰作。C++標(biāo)準(zhǔn)庫(kù)的一個(gè)重要組成部分,,它由Stepanov and Lee等人最先開(kāi)發(fā),,它是與C++幾乎同時(shí)開(kāi)始開(kāi)發(fā)的;一開(kāi)始STL選擇了Ada作為實(shí)現(xiàn)語(yǔ)言,,但Ada有點(diǎn)不爭(zhēng)氣,,最后他們選擇了C++,C++中已經(jīng)有了模板,。STL又被添加進(jìn)了C++庫(kù),。1996年,惠普公司又免費(fèi)公開(kāi)了STL,,為STL的推廣做了很大的貢獻(xiàn),。STL提供了類(lèi)型安全、高效而易用特性的STL無(wú)疑是最值得C++程序員驕傲的部分,。每一個(gè)C++程序員都應(yīng)該好好學(xué)習(xí)STL,。大體上包括container(容器)、algorithm(算法)和iterator(迭代器),,容器和算法通過(guò)迭代器可以進(jìn)行無(wú)縫連接。

 

一,、基礎(chǔ)知識(shí)

1,、泛型技術(shù)

泛型技術(shù)的實(shí)現(xiàn)方法有多種,,比如模板,多態(tài)等,。模板是編譯時(shí)決定,,多態(tài)是運(yùn)行時(shí)決定,其他的比如RTTI也是運(yùn)行時(shí)確定,。多態(tài)是依靠虛表在運(yùn)行時(shí)查表實(shí)現(xiàn)的,。比如一個(gè)類(lèi)擁有虛方法,那么這個(gè)類(lèi)的實(shí)例的內(nèi)存起始地址就是虛表地址,,可以把內(nèi)存起始地址強(qiáng)制轉(zhuǎn)換成int*,,取得虛表,然后(int*)*(int*)取得虛表里的第一個(gè)函數(shù)的內(nèi)存地址,,然后強(qiáng)制轉(zhuǎn)換成函數(shù)類(lèi)型,,即可調(diào)用來(lái)驗(yàn)證虛表機(jī)制。

泛型編程(generic programming,,以下直接以GP稱(chēng)呼)是一種全新的程序設(shè)計(jì)思想,,和OOOB,,PO這些為人所熟知的程序設(shè)計(jì)想法不同的是GP抽象度更高,,基于GP設(shè)計(jì)的組件之間偶合度底,沒(méi)有繼承關(guān)系,,所以其組件間的互交性和擴(kuò)展性都非常高,。我們都知道,任何算法都是作用在一種特定的數(shù)據(jù)結(jié)構(gòu)上的,,最簡(jiǎn)單的例子就是快速排序算法最根本的實(shí)現(xiàn)條件就是所排序的對(duì)象是存貯在數(shù)組里面,,因?yàn)榭焖倥判蚓褪且驗(yàn)橐玫綌?shù)組的隨機(jī)存儲(chǔ)特性,即可以在單位時(shí)間內(nèi)交換遠(yuǎn)距離的對(duì)象,,而不只是相臨的兩個(gè)對(duì)象,,而如果用聯(lián)表去存儲(chǔ)對(duì)象,由于在聯(lián)表中取得對(duì)象的時(shí)間是線性的即O[n],,這樣將使快速排序失去其快速的特點(diǎn),。也就是說(shuō),我們?cè)谠O(shè)計(jì)一種算法的時(shí)候,,我們總是先要考慮其應(yīng)用的數(shù)據(jù)結(jié)構(gòu),,比如數(shù)組查找,聯(lián)表查找,,樹(shù)查找,,圖查找其核心都是查找,但因?yàn)樽饔玫臄?shù)據(jù)結(jié)構(gòu)不同將有多種不同的表現(xiàn)形式,。數(shù)據(jù)結(jié)構(gòu)和算法之間這樣密切的關(guān)系一直是我們以前的認(rèn)識(shí),。泛型設(shè)計(jì)的根本思想就是想把算法和其作用的數(shù)據(jù)結(jié)構(gòu)分離,,也就是說(shuō),我們?cè)O(shè)計(jì)算法的時(shí)候并不去考慮我們?cè)O(shè)計(jì)的算法將作用于何種數(shù)據(jù)結(jié)構(gòu)之上,。泛型設(shè)計(jì)的理想狀態(tài)是一個(gè)查找算法將可以作用于數(shù)組,,聯(lián)表,樹(shù),,圖等各種數(shù)據(jù)結(jié)構(gòu)之上,,變成一個(gè)通用的,泛型的算法,。

2,、四種類(lèi)型轉(zhuǎn)換操作符

static_cast     將一個(gè)值以符合邏輯的方式轉(zhuǎn)換。應(yīng)用到類(lèi)的指針上,,意思是說(shuō)它允許子類(lèi)類(lèi)型的指針轉(zhuǎn)換為父類(lèi)類(lèi)型的指針(這是一個(gè)有效的隱式轉(zhuǎn)換),,同時(shí),也能夠執(zhí)行相反動(dòng)作:轉(zhuǎn)換父類(lèi)為它的子類(lèi),。

例如:float x;

      Count<<static_cast<int>(x);//x作為整型值輸出

 

dynamic_cast              將多態(tài)類(lèi)型向下轉(zhuǎn)換為其實(shí)際靜態(tài)類(lèi)型,。只用于對(duì)象的指針和引用。當(dāng)用于多態(tài)類(lèi)型時(shí),,它允許任意的隱式類(lèi)型轉(zhuǎn)換以及相反過(guò)程,。dynamic_cast會(huì)檢查操作是否有效。也就是說(shuō),,它會(huì)檢查轉(zhuǎn)換是否會(huì)返回一個(gè)被請(qǐng)求的有效的完整對(duì)象,。檢測(cè)在運(yùn)行時(shí)進(jìn)行。如果被轉(zhuǎn)換的指針不是一個(gè)被請(qǐng)求的有效完整的對(duì)象指針,,返回值為NULL.      

例如:class Car;

         class Cabriolet:public Car{

        

};

         class Limousline:public Car{

        

};

         void f(Car *cp)

         {

              Cabriolet *p = dynamic_cast< Cabriolet > cp;

}

 

reinterpret_cast   轉(zhuǎn)換一個(gè)指針為其它類(lèi)型的指針,。它也允許從一個(gè)指針轉(zhuǎn)換為整數(shù)類(lèi)型。反之亦然,。這個(gè)操作符能夠在非相關(guān)的類(lèi)型之間轉(zhuǎn)換,。操作結(jié)果只是簡(jiǎn)單的從一個(gè)指針到別的指針的值的二進(jìn)制拷貝。在類(lèi)型之間指向的內(nèi)容不做任何類(lèi)型的檢查和轉(zhuǎn)換,。

例如:

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B *>(a);

 

const_cast一般用于強(qiáng)制消除對(duì)象的常量性,。

例如:

class C {};
const C *a = new C;
C *b = const_cast<C *>(a);
其它三種操作符是不能修改一個(gè)對(duì)象的常量性的。

 

3,、explicit修飾的構(gòu)造函數(shù)不能擔(dān)任轉(zhuǎn)換函數(shù),。在很多情況下,隱式轉(zhuǎn)換是有意的,,并且是正當(dāng)?shù)?。但有時(shí)我們不希望進(jìn)行這種自動(dòng)的轉(zhuǎn)換。

例如:為了避免這樣的隱式轉(zhuǎn)換,,應(yīng)該象下面這樣顯式聲明該帶單一參數(shù)的構(gòu)造函數(shù):

class String {
int size;
char *p;
//..
public:
       // 不要隱式轉(zhuǎn)換
       explicit String (int sz);
       String (const char *s, int size n = 0); // 隱式轉(zhuǎn)換
};
void f ()
{
    String s(10);
    s = 100; // 現(xiàn)在編譯時(shí)出錯(cuò),;需要顯式轉(zhuǎn)換:
    s = String(100); // 好,;顯式轉(zhuǎn)換
    s = "st";        // 好,;此時(shí)允許隱式轉(zhuǎn)換
}

 

4,、命名空間namespace

   解決在使用不同模塊和程序庫(kù)時(shí),出現(xiàn)名稱(chēng)沖突問(wèn)題,。

5,、C++標(biāo)準(zhǔn)程序庫(kù)中的通用工具。由類(lèi)和函數(shù)構(gòu)成,。這些工具包括:

   數(shù)種通用類(lèi)型

   一些重要的C函數(shù)

   數(shù)值極值

 

二,、STL六大組件

容器(Container)

算法(Algorithm)

迭代器(Iterator)

仿函數(shù)(Function object)

適配器(Adaptor)

空間配置器allocator)

1、容器

作為STL的最主要組成部分--容器,,分為向量(vector),,雙端隊(duì)列(deque),表(list),,隊(duì)列(queue),,堆棧(stack),集合(set),,多重集合(multiset),,映射(map),多重映射(multimap),。

容器

特性

所在頭文件

向量vector

可以用常數(shù)時(shí)間訪問(wèn)和修改任意元素,,在序列尾部進(jìn)行插入和刪除時(shí),具有常數(shù)時(shí)間復(fù)雜度,,對(duì)任意項(xiàng)的插入和刪除就有的時(shí)間復(fù)雜度與到末尾的距離成正比,,尤其對(duì)向量頭的添加和刪除的代價(jià)是驚人的高的

<vector>

雙端隊(duì)列deque

基本上與向量相同,唯一的不同是,,其在序列頭部插入和刪除操作也具有常量時(shí)間復(fù)雜度

<deque>

list

對(duì)任意元素的訪問(wèn)與對(duì)兩端的距離成正比,,但對(duì)某個(gè)位置上插入和刪除一個(gè)項(xiàng)的花費(fèi)為常數(shù)時(shí)間。

<list>

隊(duì)列queue

插入只可以在尾部進(jìn)行,,刪除,、檢索和修改只允許從頭部進(jìn)行。按照先進(jìn)先出的原則,。

<queue>

堆棧stack

堆棧是項(xiàng)的有限序列,,并滿足序列中被刪除、檢索和修改的項(xiàng)只能是最近插入序列的項(xiàng),。即按照后進(jìn)先出的原則

<stack>

集合set

由節(jié)點(diǎn)組成的紅黑樹(shù),,每個(gè)節(jié)點(diǎn)都包含著一個(gè)元素,節(jié)點(diǎn)之間以某種作用于元素對(duì)的謂詞排列,,沒(méi)有兩個(gè)不同的元素能夠擁有相同的次序,,具有快速查找的功能,。但是它是以犧牲插入刪除操作的效率為代價(jià)的

<set>

多重集合multiset

和集合基本相同,但可以支持重復(fù)元素具有快速查找能力

<set>

映射map

{鍵,,值}對(duì)組成的集合,,以某種作用于鍵對(duì)上的謂詞排列。具有快速查找能力

<map>

多重集合multimap

比起映射,,一個(gè)鍵可以對(duì)應(yīng)多了值,。具有快速查找能力

<map>

STL容器能力表:

 

 

2算法

算法部分主要由頭文件<algorithm>,,<numeric>和<functional>組成,。< algorithm>是所有STL頭文件中最大的一個(gè),它是由一大堆模版函數(shù)組成的,,可以認(rèn)為每個(gè)函數(shù)在很大程度上都是獨(dú)立的,,其中常用到的功能范 圍涉及到比較、交換,、查找,、遍歷操作、復(fù)制,、修改,、移除、反轉(zhuǎn),、排序,、合并等等。<numeric>體積很小,,只包括幾個(gè)在序列上面進(jìn)行簡(jiǎn)單數(shù)學(xué)運(yùn)算的模板函數(shù),,包括加法和乘法在序列上的一些操作。<functional>中則定義了一些模板類(lèi),,用以聲明函數(shù)對(duì)象,。

STL的算法也是非常優(yōu)秀的,它們大部分都是類(lèi)屬的,,基本上都用到了C++的模板來(lái)實(shí)現(xiàn),,這樣,很多相似的函數(shù)就不用自己寫(xiě)了,,只要用函數(shù)模板就可以了,。

我們使用算法的時(shí)候,要針對(duì)不同的容器,,比如:對(duì)集合的查找,,最好不要用通用函數(shù)find(),它對(duì)集合使用的時(shí)候,性能非常的差,,最好用集合自帶的find()函數(shù),,它針對(duì)了集合進(jìn)行了優(yōu)化,性能非常的高,。

 

3,、迭代器

它的具體實(shí)現(xiàn)在<itertator>中,我們完全可以不管迭代器類(lèi)是怎么實(shí)現(xiàn)的,,大多數(shù)的時(shí)候,,把它理解為指針是沒(méi)有問(wèn)題的(指針是迭代器的一個(gè)特例,它也屬于迭代器),,但是,決不能完全這么做,。

迭代器功能

輸入迭代器

Input iterator

向前讀

Reads forward

istream

輸出迭代器

Output iterator

向前寫(xiě)

Writes forward

ostream,inserter

前向迭代器

Forward iterator

向前讀寫(xiě)

Read and Writes forward

 

雙向迭代器

Bidirectional iterator

向前向后讀寫(xiě)

Read and Writes forward and

backward

list,set,multiset,map,mul

timap

隨機(jī)迭代器

Random access iterator

隨機(jī)讀寫(xiě)

Read and Write with random

access

vector,deque,array,string

 

4,、仿函數(shù)

仿函數(shù),又或叫做函數(shù)對(duì)象,,是STL六大組件之一,;仿函數(shù)雖然小,但卻極大的拓展了算法的功能,,幾乎所有的算法都有仿函數(shù)版本,。例如,查找算法find_if就是對(duì)find算法的擴(kuò)展,,標(biāo)準(zhǔn)的查找是兩個(gè)元素相等就找到了,,但是什么是相等在不同情況下卻需要不同的定義,如地址相等,,地址和郵編都相等,,雖然這些相等的定義在變,但算法本身卻不需要改變,,這都多虧了仿函數(shù),。仿函數(shù)(functor)又稱(chēng)之為函數(shù)對(duì)象(function object),其實(shí)就是重載了()操作符的struct,,沒(méi)有什么特別的地方,。

如以下代碼定義了一個(gè)二元判斷式functor:

struct IntLess
{
bool operator()(int left, int right) const
{
   return (left < right);
};
};

為什么要使用仿函數(shù)呢?

1).仿函數(shù)比一般的函數(shù)靈活,。

2).仿函數(shù)有類(lèi)型識(shí)別,,可以作為模板參數(shù)。

3).執(zhí)行速度上仿函數(shù)比函數(shù)和指針要更快的,。

怎么使用仿函數(shù),?

除了在STL里,別的地方你很少會(huì)看到仿函數(shù)的身影。而在STL里仿函數(shù)最常用的就是作為函數(shù)的參數(shù),,或者模板的參數(shù),。

STL里有自己預(yù)定義的仿函數(shù),比如所有的運(yùn)算符,,=,,-,*,,,、比如'<'號(hào)的仿函數(shù)是less

template<class _Ty>
struct less   : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
        bool operator()(const _Ty& _Left, const _Ty& _Right) const
                   { // apply operator< to operands
                              return (_Left < _Right);
                   }
};

從上面的定義可以看出,less從binary_function<...>繼承來(lái)的,,那么binary_function又是什么的,?

template<class _Arg1, class _Arg2, class _Result>
struct binary_function
{ // base class for binary functions
        typedef _Arg1 first_argument_type;
        typedef _Arg2 second_argument_type;
      typedef _Result result_type;

};

其實(shí)binary_function只是做一些類(lèi)型聲明而已,別的什么也沒(méi)做,,但是在STL里為什么要做這些呢,?如果你要閱讀過(guò)STL的源碼,你就會(huì)發(fā)現(xiàn),,這樣的用法很多,,其實(shí)沒(méi)有別的目的,就是為了方便,,安全,,可復(fù)用性等。但是既然STL里面內(nèi)定如此了,,所以作為程序員你必須要遵循這個(gè)規(guī)則,否則就別想安全的使用STL,。

比如我們自己定一個(gè)仿函數(shù)??梢赃@樣:

template <typename type1,typename type2>
class func_equal :public binary_function<type1,type2,bool>
{
        inline bool operator()(type1 t1,type2 t2) const//這里的const不能少
            {
                 return t1 == t2;//當(dāng)然這里要overload==

             }
}

我們看這一行: inline bool operator()(type1 t1,type2 t2) const//這里的const不能少
inline是聲明為內(nèi)聯(lián)函數(shù),,我想這里應(yīng)該不用多說(shuō)什么什么了,關(guān)鍵是為什么要聲明為const的,?要想找到原因還是看源碼,,加入如果我們這里寫(xiě)一行代碼,find_if(s.begin(),s.end(),bind2nd(func_equal(),temp)),在bind2nd函數(shù)里面的參數(shù)是const類(lèi)型的,,const類(lèi)型的對(duì)象,,只能訪問(wèn)cosnt修飾的函數(shù)!

binary_function(二元函數(shù))相對(duì)的是unary_function(一元函數(shù)),其用法同binary_function

struct unary_function {
typedef _A argument_type;
typedef _R result_type;
};

注:仿函數(shù)就是重載()的class,,并且重載函數(shù)要為const的,,如果要自定義仿函數(shù),并且用于STL接配器,,那么一定要從binary_function或者,,unary_function繼承,。

 

5適配器

適配器是用來(lái)修改其他組件接口的STL組件,,是帶有一個(gè)參數(shù)的類(lèi)模板(這個(gè)參數(shù)是操作的值的數(shù)據(jù)類(lèi)型),。STL定義了3種形式的適配器:容器適配器,迭代器適配器,,函數(shù)適配器,。

容器適配器:包括棧(stack)、隊(duì)列(queue),、優(yōu)先(priority_queue),。使用容器適配器,stack就可以被實(shí)現(xiàn)為基本容器類(lèi)型(vector,dequeue,list)的適配,??梢园?/SPAN>stack看作是某種特殊的vctor,deque或者list容器,只是其操作仍然受到stack本身屬性的限制,。queuepriority_queue與之類(lèi)似,。容器適配器的接口更為簡(jiǎn)單,只是受限比一般容器要多,。

迭代器適配器:修改為某些基本容器定義的迭代器的接口的一種STL組件。反向迭代器和插入迭代器都屬于迭代器適配器,,迭代器適配器擴(kuò)展了迭代器的功能,。

函數(shù)適配器:通過(guò)轉(zhuǎn)換或者修改其他函數(shù)對(duì)象使其功能得到擴(kuò)展。這一類(lèi)適配器有否定器(相當(dāng)于""操作),、綁定器,、函數(shù)指針適配器。函數(shù)對(duì)象適配器的作用就是使函數(shù)轉(zhuǎn)化為函數(shù)對(duì)象,,或是將多參數(shù)的函數(shù)對(duì)象轉(zhuǎn)化為少參數(shù)的函數(shù)對(duì)象,。

例如:

STL程序里,有的算法需要一個(gè)一元函數(shù)作參數(shù),,就可以用一個(gè)適配器把一個(gè)二元函數(shù)和一個(gè)數(shù)值,,綁在一起作為一個(gè)一元函數(shù)傳給算法。
例如:

find_if(coll.begin(), coll.end(), bind2nd(greater <int>(), 42));
這句話就是找coll中第一個(gè)大于42的元素,。

greater <int>()
,,其實(shí)就是">"號(hào),是一個(gè)2元函數(shù)

bind2nd
的兩個(gè)參數(shù),,要求一個(gè)是2元函數(shù),一個(gè)是數(shù)值,,結(jié)果是一個(gè)1元函數(shù),。

bind2nd
就是個(gè)函數(shù)適配器。

 

6空間配置器

STL的內(nèi)存配置器在我們的實(shí)際應(yīng)用中幾乎不用涉及,但它卻在STL的各種容器背后默默做了大量的工作,STL內(nèi)存配置器為容器分配并管理內(nèi)存。統(tǒng)一的內(nèi)存管理使得STL庫(kù)的可用性、可移植行,、以及效率都有了很大的提升,。

SGI-STL的空間配置器有2種,,一種僅僅對(duì)c語(yǔ)言的mallocfree進(jìn)行了簡(jiǎn)單的封裝,,而另一個(gè)設(shè)計(jì)到小塊內(nèi)存的管理等,運(yùn)用了內(nèi)存池技術(shù)等。在SGI-STL中默認(rèn)的空間配置器是第二級(jí)的配置器。

SGI使用時(shí)std::alloc作為默認(rèn)的配置器,。

A).a(chǎn)lloc把內(nèi)存配置和對(duì)象構(gòu)造的操作分開(kāi),,分別由alloc::allocate()::construct()負(fù)責(zé),,同樣內(nèi)存釋放和對(duì)象析夠操作也被分開(kāi)分別由alloc::deallocate()::destroy()負(fù)責(zé),。這樣可以保證高效,因?yàn)閷?duì)于內(nèi)存分配釋放和構(gòu)造析夠可以根據(jù)具體類(lèi)型(type traits)進(jìn)行優(yōu)化,。比如一些類(lèi)型可以直接使用高效的memset來(lái)初始化或者忽略一些析構(gòu)函數(shù),。對(duì)于內(nèi)存分配alloc也提供了2級(jí)分配器來(lái)應(yīng)對(duì)不同情況的內(nèi)存分配。

B).第一級(jí)配置器直接使用malloc()和free()來(lái)分配和釋放內(nèi)存,。第二級(jí)視情況采用不同的策略:當(dāng)需求內(nèi)存超過(guò)128bytes的時(shí)候,,視為足夠大,便調(diào)用第一級(jí)配置器,;當(dāng)需求內(nèi)存小于等于128bytes的時(shí)候便采用比較復(fù)雜的memeory pool的方式管理內(nèi)存,。

C).無(wú)論allocal被定義為第一級(jí)配置器還是第二級(jí),SGI還為它包裝一個(gè)接口,,使得配置的接口能夠符合標(biāo)準(zhǔn)即把配置單位從bytes轉(zhuǎn)到了元素的大?。?/SPAN>

                  template<class T, class Alloc>

class simple_alloc

{

public:

     static T* allocate(size_t n)

     {

         return 0 == n ? 0 : (T*)Alloc::allocate(n * sizeof(T));

     }

 

     static T* allocate(void)

     {

         return (T*) Alloc::allocate(sizeof(T));

     }

 

     static void deallocate(T* p, size_t n)

     {

         if (0 != n) Alloc::deallocate(p, n * sizeof(T));

     }

 

     static void deallocate(T* p)

     {

         Alloc::deallocate(p, sizeof(T));

     }

}   

 

d).內(nèi)存的基本處理工具,,它們均具有commt or rollback能力。

template<class InputIterator, class ForwardIterator>

ForwardIterator

uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result);

 

template<class ForwardIterator, class T>

void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x);

 

template<class ForwardIterator, class Size, class T>

ForwardIterator

uninitialized_fill_n(ForwardIterator first, ForwardIterator last, const T& x)

 

三,、具體容器,、算法

1、所有容器都提供了一個(gè)默認(rèn)的構(gòu)造函數(shù),,一個(gè)拷貝構(gòu)造函數(shù),。

例如:

list<int> l;

....

vector<int> ivector(l.begin(),l.end());

 

int array[]={1,2,3,4};

....

set<int> iset(array,array+sizeof(array)/sizeof(array[0]));

 

2、與大小相關(guān)的函數(shù)

size(),empty(),max_size()

3,、返回迭代器的函數(shù)

begin(),end(),rbegin(),rend()

4,、比較操作

==,!=,<,>,>=....

 

Vector詳解:

capacity(),返回vector能夠容納的元素個(gè)數(shù)。

size(),返回vector內(nèi)現(xiàn)有元素的個(gè)數(shù),。

賦值操作:

c1=c2; 把c2的全部元素指派給c1

c.assign(n,elem);復(fù)制n個(gè)elem,,指派給c

c.assign(beg,end);將區(qū)間beg,end內(nèi)的元素指派給c

c1.swap(c2);將c1,c2元素互換

swap(c1,c2);同上

元素存取

c.at(index);

c[index];

c.front();返回第一個(gè)元素

c.back();

 

插入和刪除:

c.insert(pos.elem);

c.insert(pos,n.elem); 插入n個(gè)elem

c.insert(pos,beg,end); 在pos出插入beg,,end區(qū)間內(nèi)的所有元素,。

c.push_back(elem);

c.pop_back();

c.erase(pos); 刪除pos上的元素,返回下一個(gè)元素

c.erase(beg,end);

c.resize(num);將元素?cái)?shù)量改為num,,如果size變大了,,多出來(lái)的新元素都要一default方式構(gòu)建。

c.resize(num,elem);將元素?cái)?shù)量改為num,,如果size變大了,,多出來(lái)的新元素是elem的副本。

c.clear();刪除所有,。

 

vector的reserve和resize

reserve只分配空間,,而不創(chuàng)建對(duì)象,size()不變,。而resize分配空間而且用空對(duì)象填充.

reserve是容器預(yù)留空間,,但并不真正創(chuàng)建元素對(duì)象,在創(chuàng)建對(duì)象之前,,不能引用容器內(nèi)的元素,,因此當(dāng)加入新的元素時(shí),需要用push_back()/insert()函數(shù),。

resize是改變?nèi)萜鞯拇笮?,并且?chuàng)建對(duì)象,因此,,調(diào)用這個(gè)函數(shù)之后,,就可以引用容器內(nèi)的對(duì)象了,因此當(dāng)加入新的元素時(shí),,用operator[]操作符,,或者用迭代器來(lái)引用元素對(duì)象,。

再者,兩個(gè)函數(shù)的形式是有區(qū)別的,,reserve函數(shù)之后一個(gè)參數(shù),,即需要預(yù)留的容器的空間;resize函數(shù)可以有兩個(gè)參數(shù),,第一個(gè)參數(shù)是容器新的大小,,第二個(gè)參數(shù)是要加入容器中的新元素,如果這個(gè)參數(shù)被省略,,那么就調(diào)用元素對(duì)象的默認(rèn)構(gòu)造函數(shù),。

vector有而deque無(wú)的:capacity(), reserve();

deque有而vector無(wú)的:push_front(elem), pop_front(); push_back(elem), pop_back();

STL提供的另兩種容器queue、stack,,其實(shí)都只不過(guò)是一種adaptor,,它們簡(jiǎn)單地修飾deque的界面而成為另外的容器類(lèi)型

 

List詳解:

for_each  (.begin(), .end(), “函數(shù)”);

count (.begin(), .end(), 100, jishuqi);

返回對(duì)象等于100的個(gè)數(shù)jishuqi值。

count_if() 帶一個(gè)函數(shù)對(duì)象的參數(shù)(上面“100”的這個(gè)參數(shù)),。函數(shù)對(duì)象是一個(gè)至少帶有一個(gè)operator()方法的類(lèi),。這個(gè)類(lèi)可以更復(fù)雜。

find(*.begin().*end(),“要找的東西”),;

如果沒(méi)有找到指出的對(duì)象,,就會(huì)返回*.end()的值,要是找到了就返回一個(gè)指著找到的對(duì)象的iterator

fine_if(),;與count_if()類(lèi)似,,是find的更強(qiáng)大版本。

STL通用算法search()用來(lái)搜索一個(gè)容器,,但是是搜索一個(gè)元素串,,不象find()和find_if() 只搜索單個(gè)的元素。

search算法在一個(gè)序列中找另一個(gè)序列的第一次出現(xiàn)的位置,。

search(A.begin(), A.end(), B.begin(), B.end());

A中找B這個(gè)序列的第一次出現(xiàn),。

要排序一個(gè)list,我們要用list的成員函數(shù)sort(),,而不是通用算法sort()。

list容器有它自己的sort算法,,這是因?yàn)橥ㄓ盟惴▋H能為那些提供隨機(jī)存取里面元素 的容器排序,。

list的成員函數(shù)push_front()和push_back()分別把元素加入到list的前面和后面。你可以使用insert() 把對(duì)象插入到list中的任何地方,。

insert()可以加入一個(gè)對(duì)象,,一個(gè)對(duì)象的若干份拷貝,或者一個(gè)范圍以?xún)?nèi)的對(duì)象,。

list成員函數(shù)pop_front()刪掉list中的第一個(gè)元素,,pop_back()刪掉最后一個(gè)元素,。函數(shù)erase()刪掉由一個(gè)iterator指出的元素。還有另一個(gè)erase()函數(shù)可以刪掉一個(gè)范圍的元素,。

list的成員函數(shù)remove()用來(lái)從list中刪除元素,。

*.remove("要?jiǎng)h除的對(duì)象");

通用算法remove()使用和list的成員函數(shù)不同的方式工作。一般情況下不改變?nèi)萜鞯拇笮 ?

remove(*.begin(),*.end(),"要?jiǎng)h除的對(duì)象");

使用STL通用算法stable_partition()和list成員函數(shù)splice()來(lái)劃分一個(gè)list,。

stable_partition()是一個(gè)有趣的函數(shù),。它重新排列元素,使得滿足指定條件的元素排在不滿足條件的元素前面,。它維持著兩組元素的順序關(guān)系,。

splice 把另一個(gè)list中的元素結(jié)合到一個(gè)list中。它從源list中刪除元素,。

 

Set Map詳解:

STL map和set的使用雖不復(fù)雜,,但也有一些不易理解的地方,如:

為何map和set的插入刪除效率比用其他序列容器高,?

為何每次insert之后,,以前保存的iterator不會(huì)失效?

為何map和set不能像vector一樣有個(gè)reserve函數(shù)來(lái)預(yù)分配數(shù)據(jù),?

當(dāng)數(shù)據(jù)元素增多時(shí)(10000到20000個(gè)比較),,map和set的插入和搜索速度變化如何?

C++ STL中標(biāo)準(zhǔn)關(guān)聯(lián)容器set, multiset, map, multimap內(nèi)部采用的就是一種非常高效的平衡檢索二叉樹(shù):紅黑樹(shù),,也成為RB樹(shù)(Red-Black Tree),。RB樹(shù)的統(tǒng)計(jì)性能要好于一般的平衡二叉樹(shù)(AVL-樹(shù)).

為何map和set的插入刪除效率比用其他序列容器高?

大部分人說(shuō),,很簡(jiǎn)單,,因?yàn)閷?duì)于關(guān)聯(lián)容器來(lái)說(shuō),不需要做內(nèi)存拷貝和內(nèi)存移動(dòng),。說(shuō)對(duì)了,,確實(shí)如此。map和set容器內(nèi)所有元素都是以節(jié)點(diǎn)的方式來(lái)存儲(chǔ),,其節(jié)點(diǎn)結(jié)構(gòu)和鏈表差不多,,指向父節(jié)點(diǎn)和子節(jié)點(diǎn)。這里的一切操作就是指針換來(lái)?yè)Q去,,和內(nèi)存移動(dòng)沒(méi)有關(guān)系,。

為何每次insert之后,以前保存的iterator不會(huì)失效,?(同解)

為何map和set不能像vector一樣有個(gè)reserve函數(shù)來(lái)預(yù)分配數(shù)據(jù),?

究其原理來(lái)說(shuō)時(shí),引起它的原因在于在map和set內(nèi)部存儲(chǔ)的已經(jīng)不是元素本身了,而是包含元素的節(jié)點(diǎn),。

其實(shí)你就記住一點(diǎn),,在map和set內(nèi)面的分配器已經(jīng)發(fā)生了變化,reserve方法你就不要奢望了,。

當(dāng)數(shù)據(jù)元素增多時(shí)(10000和20000個(gè)比較),,map和set的插入和搜索速度變化如何?

如果你知道log2的關(guān)系你應(yīng)該就徹底了解這個(gè)答案,。在map和set中查找是使用二分查找,,也就是說(shuō),如果有16個(gè)元素,,最多需要比較4次就能找到結(jié)果,,有32個(gè)元素,最多比較5次,。那么有10000個(gè)呢,?最多比較的次數(shù)為log10000,最多為14次,,如果是20000個(gè)元素呢,?最多不過(guò)15次。

 

泛型算法:

所有算法的前兩個(gè)參數(shù)都是一對(duì)iterators:[first,,last),,用來(lái)指出容器內(nèi)一個(gè)范圍內(nèi)的元素。

每個(gè)算法的聲明中,,都表現(xiàn)出它所需要的最低層次的iterator類(lèi)型,。

 

常用算法:

accumulate() 元素累加

adjacent_difference() 相鄰元素的差額

adjacent_find() 搜尋相鄰的重復(fù)元素

binary_search() 二元搜尋

copy() 復(fù)制

copy_backward() 逆向復(fù)制

count() 計(jì)數(shù)

count_if() 在特定條件下計(jì)數(shù)

equal() 判斷相等與否

equal_range() 判斷相等與否(傳回一個(gè)上下限區(qū)間范圍)

fill() 改填元素值

fill_n() 改填元素值,n 次

find() 搜尋

find_if() 在特定條件下搜尋

find_end() 搜尋某個(gè)子序列的最后一次出現(xiàn)地點(diǎn)

find_first_of() 搜尋某些元素的首次出現(xiàn)地點(diǎn)

for_each() 對(duì)范圍內(nèi)的每一個(gè)元素施行某動(dòng)作

generate() 以指定動(dòng)作的運(yùn)算結(jié)果充填特定范圍內(nèi)的元素

generate_n() 以指定動(dòng)作的運(yùn)算結(jié)果充填 n 個(gè)元素內(nèi)容

includes() 涵蓋於

inner_product() 內(nèi)積

inplace_merge() 合并并取代(覆寫(xiě))

iter_swap() 元素互換

lexicographical_compare() 以字典排列方式做比較

lower_bound() 下限

max() 最大值

max_element() 最大值所在位置

min() 最小值

min_element() 最小值所在位置

merge() 合并兩個(gè)序列

mismatch() 找出不吻合點(diǎn)

next_permutation() 獲得下一個(gè)排列組合

泛型演算法(Generic Algorithms)與 Function Obje4 cts

nth_element() 重新安排序列中第n個(gè)元素的左右兩端

partial_sort() 局部排序

partial_sort_copy() 局部排序并復(fù)制到它處

partial_sum() 局部總和

partition() 切割

prev_permutation() 獲得前一個(gè)排列組合

random_shuffle() 隨機(jī)重排

remove() 移除某種元素(但不刪除)

remove_copy() 移除某種元素并將結(jié)果復(fù)制到另一個(gè) container

remove_if() 有條件地移除某種元素

remove_copy_if() 有條件地移除某種元素并將結(jié)果復(fù)制到另一個(gè) container

replace() 取代某種元素

replace_copy() 取代某種元素,,并將結(jié)果復(fù)制到另一個(gè) container

replace_if() 有條件地取代

replace_copy_if() 有條件地取代,,并將結(jié)果復(fù)制到另一個(gè) container

reverse() 顛倒元素次序

reverse_copy() 顛倒元素次序并將結(jié)果復(fù)制到另一個(gè) container

rotate() 旋轉(zhuǎn)

rotate_copy() 旋轉(zhuǎn),并將結(jié)果復(fù)制到另一個(gè) container

search() 搜尋某個(gè)子序列

search_n() 搜尋「連續(xù)發(fā)生 n 次」的子序列

set_difference() 差集

set_intersection() 交集

set_symmetric_difference() 對(duì)稱(chēng)差集

set_union() 聯(lián)集

sort() 排序

stable_partition() 切割并保持元素相對(duì)次序

stable_sort() 排序并保持等值元素的相對(duì)次序

swap() 置換(對(duì)調(diào))

swap_range() 置換(指定范圍)

transform() 以?xún)蓚€(gè)序列為基礎(chǔ),,交互作用產(chǎn)生第三個(gè)序列

unique() 將重復(fù)的元素摺疊縮編,,使成唯一

unique_copy() 將重復(fù)的元素摺疊縮編,使成唯一,,并復(fù)制到他處

upper_bound() 上限

 

 

四,、注意細(xì)節(jié):

1auto_ptr 不能用new[]所生成的array作為初值,,因?yàn)獒尫艃?nèi)存時(shí)用的是delete,,而不是delete[]

2、就搜尋速度而言,,hash table通常比二叉樹(shù)還要快5~10倍。hash table不是C++標(biāo)準(zhǔn)程序庫(kù)的一員,。

3,、迭代器使用過(guò)程中優(yōu)先選用前置式遞增操作符(++iter)而不是選擇后置式遞增操作符(iter++),。

3、迭代器三個(gè)輔助函數(shù):advance(),distance(),iter_swap(),。

       advance()可令迭代器前進(jìn)

       distance()可處理迭代器之間的距離,。

       iter_swap()可交換兩個(gè)迭代器所指內(nèi)容。

4,、hasp函數(shù) makeheap(),、push_heap()pop_heap(),、sort_heap()

5,、’/0’string之中并不具有特殊意義,但是在一般C形式的string中卻用來(lái)標(biāo)記字符串結(jié)束,。在string中,,字符 ‘/0’和其他字符的地位完全相同。string中有三個(gè)函數(shù)可以將字符串內(nèi)容轉(zhuǎn)換成字符數(shù)組或C形式的string,。

data()     以字符數(shù)組的形式返回字符串內(nèi)容,。但末未追加’/0’字符,返回類(lèi)型并非有效的C形式string,。

c_str()    C形式返回字符串內(nèi)容(在末尾端添加’/0’字符),。

copy()    將字符串內(nèi)容復(fù)制到“調(diào)用者提供的字符數(shù)組”中,不添加’/0’字符,。

6,、容器中用empty來(lái)代替檢查size是否為0;當(dāng)使用new得到指針的容器時(shí),,切記在容器銷(xiāo)毀前delete那些指針,;千萬(wàn)不要把auto_ptr放入容器中。

7,、盡量使用vectorstring來(lái)代替動(dòng)態(tài)申請(qǐng)的數(shù)組,;避免使用vector<bool>vector<bool>有兩個(gè)問(wèn)題.第一,,它不是一個(gè)真正STL容器,,第二,它并不保存bool類(lèi)型,。

8,、迭代器使用過(guò)程中,盡量使用iterator代替const_iterator,,reverse_iteratorconst_reverse_iterator,;使用distanceadvanceconst_iterators轉(zhuǎn)化成iterators

typedef deque<int> IntDeque;  // 和以前一樣

typedef IntDeque::iterator Iter;

typedef IntDeque::const_iterator ConstIter;

IntDeque  d;

ConstIter ci;

...     // 讓ci指向d

Iter i(d.begin());    // 初始化i為d.begin()

advance(i, distance(i, ci));  // 調(diào)整i,指向ci位置

9,、避免對(duì)setmultiset的鍵值進(jìn)行修改,。

10永遠(yuǎn)讓比較函數(shù)對(duì)相同元素返回false,。

11,、排序選擇:

1)如果你需要在vector,、string,、deque或數(shù)組上進(jìn)行完全排序,你可以使用sort或stable_sort,。

2)如果你有一個(gè)vector,、string,、deque或數(shù)組,你只需要排序前n個(gè)元素,,應(yīng)該用partial_sort,。

3)如果你有一個(gè)vector、string,、deque或數(shù)組,,你需要鑒別出第n個(gè)元素或你需要鑒別出最前的n個(gè)元素,而不用知道它們的順序,,nth_element是你應(yīng)該注意和調(diào)用的,。

4)如果你需要把標(biāo)準(zhǔn)序列容器的元素或數(shù)組分隔為滿足和不滿足某個(gè)標(biāo)準(zhǔn),你大概就要找partition或stable_partition,。

5)如果你的數(shù)據(jù)是在list中,,你可以直接使用partitionstable_partition,你可以使用listsort來(lái)代替sortstable_sort,。如果你需要partial_sortnth_element提供的效果,,你就必須間接完成這個(gè)任務(wù)。
12,、如果你真的想刪除東西的話就在類(lèi)似remove的算法后接上erase,。remove從一個(gè)容器中remove元素不會(huì)改變?nèi)萜髦性氐膫€(gè)數(shù),erase是真正刪除東西,。
13
,、提防在指針的容器上使用類(lèi)似remove的算法,在調(diào)用類(lèi)似remove的算法前手動(dòng)刪除和廢棄指針,。
14,、盡量用成員函數(shù)代替同名的算法,有些容器擁有和STL算法同名的成員函數(shù),。關(guān)聯(lián)容器提供了count,、find,、lower_boundupper_boundequal_range,,而list提供了remove,、remove_ifunique,、sortmergereverse,。大多數(shù)情況下,,你應(yīng)該用成員函數(shù)代替算法。這樣做有兩個(gè)理由,。首先,,成員函數(shù)更快。其次,,比起算法來(lái),,它們與容器結(jié)合得更好(尤其是關(guān)聯(lián)容器)。那是因?yàn)橥乃惴ê统蓡T函數(shù)通常并不是是一樣的,。
15
,、容器中使用自定義的結(jié)構(gòu)體時(shí),如果用到拷貝與賦值,,結(jié)構(gòu)體需要重載operator=符號(hào),;比較容器分成相等與不等,相等時(shí)重載operator==符號(hào),,不等時(shí)重載operator<符號(hào),。比如setmap,、multiset,、multimappriority_queue等容器類(lèi)要求重載operator<符號(hào),。
16
,、Map/Multimap,Sets/Multisets都不能用push_back,push_front,因?yàn)樗亲詣?dòng)排序的,。

Set內(nèi)的相同數(shù)值的元素只能出現(xiàn)一次,,Multisets內(nèi)可包含多個(gè)數(shù)值相同的元素。

Map內(nèi)的相同數(shù)值的元素只能出現(xiàn)一次,,Multimap內(nèi)可包含多個(gè)數(shù)值相同的元素,。內(nèi)部由二叉樹(shù)實(shí)現(xiàn),便于查找,。

17,、string 與 數(shù)字之間的轉(zhuǎn)換,,轉(zhuǎn)換的方法有很多種,一般使用stringstream來(lái)實(shí)現(xiàn)轉(zhuǎn)換,。比如:

#include  <iostream>

#include  <sstream>  

#include  <string>  

using   namespace   std;  

int   main()  

{  

  int   i=0;  

  string   temp;    

  stringstream   s;  

  //string轉(zhuǎn)換為數(shù)字

  temp = “1234”; 

  s<<temp;  

  s>>i;  

  cout<<i<<endl;  

 

 //數(shù)字轉(zhuǎn)換為string

 i=256;

 s<<i;

 temp = s.str();

 cout<<temp<<end;

 

 system("pause");  

 return   0;

}

 

18,、對(duì)于自定義的結(jié)構(gòu)體,放入容器中,,最好不要對(duì)容器進(jìn)行內(nèi)存初始化(不要調(diào)用memset,zeromemory函數(shù)),,否則如果結(jié)構(gòu)體中有指針類(lèi)型的變量時(shí),就會(huì)出現(xiàn)問(wèn)題,。

 

19,、Vector的函數(shù)泄漏問(wèn)題

定義了一個(gè)

struct temp

{

     char name[256];

     int i;

}

Vector<temp> vect;

當(dāng)對(duì)這個(gè)vect執(zhí)行pushback一些temp的結(jié)構(gòu)體后,執(zhí)行clear這樣是否會(huì)內(nèi)存泄露,?可以釋放掉temp結(jié)構(gòu)體中的name內(nèi)存嗎,?

解決方法:

不行,clear只是把那些元素全部刪除掉,,并不是釋放內(nèi)存,。再者,你這樣的定義容器是不需要釋放內(nèi)存的,,如果你這樣定義,,std::vector <temp> *pVec。就需要了,。先pVec->clear() pVec->swap( (std::vector <temp>)(*pVec) ),。就能實(shí)現(xiàn)內(nèi)存的釋放。  

 

20,、stl之map erase方法的正確使用
STL的map表里有一個(gè)erase方法用來(lái)從一個(gè)map中刪除掉指令的一個(gè)節(jié)點(diǎn),,不存在任何問(wèn)題。
如果刪除多一個(gè)節(jié)點(diǎn)時(shí),,需要使用正確的調(diào)用方法,。比如下面的方法是有問(wèn)題:
for(ITER iter=mapTest.begin();iter!=mapTest.end();++iter)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter);
}
這是一種錯(cuò)誤的寫(xiě)法,會(huì)導(dǎo)致程序行為不可知.究其原因是map 是關(guān)聯(lián)容器,對(duì)于關(guān)聯(lián)容器來(lái)說(shuō),如果某一個(gè)元素已經(jīng)被刪除,,那么其對(duì)應(yīng)的迭代器就失效了,,不應(yīng)該再被使用;否則會(huì)導(dǎo)致程序無(wú)定義的行為,。

正確的使用方法:
1).使用刪除之前的迭代器定位下一個(gè)元素,。STL建議的使用方式
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
mapTest.erase(iter++);
}

或者
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
ITER iterTmp = iter;
iter++;
cout<<iterTmp->first<<":"<<iterTmp->second<<endl;
mapTest.erase(iterTmp);
}

2). erase() 成員函數(shù)返回下一個(gè)元素的迭代器
for(ITER iter=mapTest.begin();iter!=mapTest.end();)
{
cout<<iter->first<<":"<<iter->second<<endl;
iter=mapTest.erase(iter);
}

 

 

 

 

推薦書(shū)籍:

C++標(biāo)準(zhǔn)程序庫(kù)》本書(shū)將焦點(diǎn)放在標(biāo)準(zhǔn)模板庫(kù)(Standard Template Library)身上,檢驗(yàn)其中的容器(containers),、迭代器(iterators),、仿函數(shù)(functors)和算法(algorithms)。你還可以找到特殊容器,、字符串(strings),、數(shù)值類(lèi)別,、國(guó)際化議題、IOStream,。每一個(gè)組件都有深刻的呈現(xiàn),,包括其介紹、設(shè)計(jì),、運(yùn)用實(shí)例,、細(xì)部解說(shuō)、陷阱,、意想不到的危險(xiǎn),,以及相關(guān)類(lèi)別和函數(shù)的確切標(biāo)記(signature)和定義。一份見(jiàn)解深刻的基礎(chǔ)概念介紹和一個(gè)程序庫(kù)綜合鳥(niǎo)瞰,,會(huì)對(duì)新手帶來(lái)快速的提升。

《泛型編程與STL闡述了泛型程序設(shè)計(jì)的中心觀念:concepts,modeling, refinement,并為你展示這些觀念如何導(dǎo)出 STL 的基礎(chǔ)概念:iterators, containers, function objects.循此路線,你可以把 STL 想象為一個(gè)由 concepts(而非明確之 functions classes)組成的 library.你將學(xué)習(xí)其正式結(jié)構(gòu)并因此獲得其潛在威力之完整優(yōu)勢(shì).

Effective STL闡述了如何有效地使用STLStandard Template Library, 標(biāo)準(zhǔn)模板庫(kù))進(jìn)行編程,。書(shū)中講述了如何將STL組件組合在一起,,從而利用庫(kù)的設(shè)計(jì)。這些內(nèi)容會(huì)幫助你針對(duì)簡(jiǎn)單的問(wèn)題開(kāi)發(fā)出簡(jiǎn)單,、直接的解決方案,,并且針對(duì)復(fù)雜的問(wèn)題開(kāi)發(fā)出精致的解決方案。書(shū)中還描述了常見(jiàn)的STL使用錯(cuò)誤,,并告訴你如何避免這些錯(cuò)誤,。

STL源碼剖析》了解源碼,看到vector的實(shí)現(xiàn),、list的實(shí)現(xiàn),、heap的實(shí)現(xiàn)、deque的實(shí)現(xiàn),、RB-tree的實(shí)現(xiàn),、hash-table的實(shí)現(xiàn)、set/map 的實(shí)現(xiàn),;你將看到各種算法(排序,、搜尋、排列組合,、數(shù)據(jù)移動(dòng)與復(fù)制)的實(shí)現(xiàn),;你甚至將看到底層的memory pool 和高階抽象的traits 機(jī)制的實(shí)現(xiàn)。

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多