中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

阜城網(wǎng)站建設(shè)公司啟信聚客通網(wǎng)絡(luò)營銷策劃

阜城網(wǎng)站建設(shè)公司,啟信聚客通網(wǎng)絡(luò)營銷策劃,網(wǎng)頁編輯打印工具,落地頁模板網(wǎng)站文章目錄 使用STL庫的55條建議1.慎重選擇容器的類型2.不要試圖編寫?yīng)毩⒂谌萜鞯拇a3.確定容器中的對象拷貝正確且高效4.調(diào)用empty判斷是否為空,而不是size5.區(qū)間成員函數(shù)優(yōu)于與之對應(yīng)單元素成員函數(shù)6.如果容器中包含了通過new操作創(chuàng)建的指針,切記在容器…

文章目錄

  • 使用STL庫的55條建議
    • 1.慎重選擇容器的類型
    • 2.不要試圖編寫?yīng)毩⒂谌萜鞯拇a
    • 3.確定容器中的對象拷貝正確且高效
    • 4.調(diào)用empty判斷是否為空,而不是size
    • 5.區(qū)間成員函數(shù)優(yōu)于與之對應(yīng)單元素成員函數(shù)
    • 6.如果容器中包含了通過new操作創(chuàng)建的指針,切記在容器對象析構(gòu)前,要將指針delete。
    • 7.切勿創(chuàng)建包含auto_ptr的容器對象
    • 8.慎重選擇刪除元素的方法
    • 9.了解分配子allocator的約定和限制
    • 10.切勿對STL容器的線程不安全性有不切實際的依賴
    • 11.vector和string優(yōu)于動態(tài)分配的數(shù)組
    • 12.使用reserve避免不必要的重新分配
    • 13.注意string實現(xiàn)的多樣性
    • 14.了解如何將string和vector 傳給舊的API
    • 15.使用‘swap技巧’去除多余的內(nèi)存
    • 16.避免使用vector<bool>
    • 17,理解相等和等價的區(qū)別
    • 18.為包含指針的關(guān)聯(lián)函數(shù)指定比較類型
    • 19.總讓比較函數(shù)在相等的情況下返回false
    • 20.切勿直接修改set 或者 multiset的鍵
    • 21.考慮用排序vector代替關(guān)聯(lián)容器
    • 22.當(dāng)效率至關(guān)重要,謹(jǐn)慎選擇opertor[] 和insert
    • 23.使用distance 和advance將容器的const_iterator轉(zhuǎn)換為iterator
    • 24.正確理解由reverse_iterator的base()成員函數(shù)所產(chǎn)生的iterator的用法
    • 25.對于逐字符的輸入請考慮使用istreambuf_iterator
    • 26.確保目標(biāo)區(qū)間足夠大
    • 27.了解各種和排序有關(guān)的選擇
    • 28.如果確實需要刪除元素,則需要在remove這一類算法之后調(diào)用erase
    • 29.使用accumulate進行區(qū)間統(tǒng)計
    • 30.遵循按值傳遞的原則來設(shè)計函數(shù)子類
    • 31.確保判別式是純函數(shù)
    • 32.若一個類是函數(shù)子,應(yīng)該讓它可配接
    • 33.理解ptr_fun,mem_fun和mem_fun_ref的由來
    • 34.算法調(diào)用優(yōu)于手寫的循環(huán)
    • 35.容器的成員函數(shù)優(yōu)于同名算法
    • 35.正確區(qū)分count,find,binary_search,lower_bound,upper_bound和equal_range
    • 36.避免直寫型的代碼
    • 37.總是包含(#include)正確的頭文件
    • 36.避免直寫型的代碼
    • 37.總是包含(#include)正確的頭文件

使用STL庫的55條建議

1.慎重選擇容器的類型

根據(jù)你的業(yè)務(wù)需求和算法去選擇不同的容器,將數(shù)據(jù)結(jié)構(gòu)和算法結(jié)合起來。

c++容器類型:

  • 序列容器:其中對象有序排列,根據(jù)整數(shù)值進行索引,有vector,list,deque,string
  • 關(guān)聯(lián)容器:其中對象的順序不重要,根據(jù)鍵值進行索引,set,map,multiset,multimap
  • 適配器:調(diào)正原有容器的行為,使對外產(chǎn)生新的接口,類型和返回元素。
  • 生成器:構(gòu)造元素序列

標(biāo)準(zhǔn)容器:指的是c++標(biāo)準(zhǔn)化后的容器,遵從c++的標(biāo)準(zhǔn),不同的編譯器都支持,代碼移植能力強。vector,list,deque,string,set,map,multiset,multimap

非標(biāo)準(zhǔn)容器:指的是違背標(biāo)準(zhǔn)化后的容器,在不同版本的編譯器上可能不支持,hash_set,hast_map等等

使用參考:

例如需要按順序插入元素就需要序列容器,如果元素的順序不重要就使用關(guān)聯(lián)容器,如果就頻繁刪除容器內(nèi)元素就避免使用內(nèi)存連續(xù)的容器

2.不要試圖編寫?yīng)毩⒂谌萜鞯拇a

因為不同的容器所支持的函數(shù)和迭代器類型使不同的,可能會報錯,所以不要編寫?yīng)毩⒂谌萜鞯拇a。

3.確定容器中的對象拷貝正確且高效

當(dāng)對vector,list,deque進行元素的插入或者刪除操作時,現(xiàn)有的元素的位置通常會被移動(拷貝)。使用排序,反轉(zhuǎn)也會被移動(拷貝)??截愂荢TL的工作方式。

當(dāng)給容器中存入對象時存入的是對象的拷貝,當(dāng)從容器中取出對象時,取出的容器中對象的拷貝。所以要確保拷貝的正確和高效。

當(dāng)你創(chuàng)建的時基類對象卻存著派生類對象時,拷貝就會剝離將派生的內(nèi)容剝離。如果想要從基類容器使用派生類的虛方法,就要指針。

而且拷貝指針。

由于是拷貝的,因此在最后析構(gòu)的時候容易出問題,因此最好采用智能指針。

4.調(diào)用empty判斷是否為空,而不是size

首先empty一般是內(nèi)聯(lián)函數(shù),而且empty的時間復(fù)雜度是常數(shù)。

size不是內(nèi)聯(lián)函數(shù),而且size的時間復(fù)雜度是線性的。

5.區(qū)間成員函數(shù)優(yōu)于與之對應(yīng)單元素成員函數(shù)

給定v1和v2兩個矢量,使v1的內(nèi)容等于v2后半段內(nèi)容相同。怎么實現(xiàn)。

//1.使用區(qū)間函數(shù)
v1.assign(v2.begin()+v2.size()/2,v2.end());
//2.使用copy函數(shù),內(nèi)部還是循環(huán)
v1.clear();
copy(v2.begin()+v2.size()/2,v2.end(),back_inserter(v1));
//3.使用insert,這樣v1是反著的,因此每次都插到v1前面
insert(v1.begin(),v2.begin()+v2.size()/2,v2.end());
//使用單元素方法
//1.使用賦值
v1.clear()
for(vector<int>::const_iterator ci=v2.begin()+v2.size()/2;ci!=v2.end();++ci){v2.push_back(ci);
}

從代碼上

  • 使用區(qū)間函數(shù),可以少寫一些代碼
  • 使用區(qū)間函數(shù),意圖更明確。
//將數(shù)組data內(nèi)的元素添加到向量v中
//使用單元素成員函數(shù)
vector<int>::iterator insertloc(v.begin());
for(int i=0;i<numValues;i++){insertloc=v.insert(insertloc,data[i]);++insertloc;
}

從效率上,調(diào)用單元素成員函數(shù)

  • 不必要的函數(shù)調(diào)用,將v.insert()函數(shù)調(diào)用numValues遍
  • 將v中已有元素頻繁的移動到插入元素的后面,每個元素移動numValues遍,如果插入元素為對象的化進行拷貝復(fù)制對象內(nèi)的參數(shù),需要的賦值次數(shù)更多。
  • 如果容器為順序存儲的容器則可能會造成內(nèi)存的多次擴充,則會把舊內(nèi)存的元素拷貝進入新內(nèi)存,并將舊內(nèi)存的東西銷毀然后插入新內(nèi)存的東西。

對于vector 和string這三條都滿足,對于deque第三條不滿足。

對于list只有第一條滿足,但是單個插入list會導(dǎo)致list需要不斷變化pre 和next的指向,沒有必要。

6.如果容器中包含了通過new操作創(chuàng)建的指針,切記在容器對象析構(gòu)前,要將指針delete。

void dosomething(){
vector<widget *>vmp;
for(int i=0;i<N;++i)vwp.push_back(new wideget);
}
//當(dāng)vmp作用域結(jié)束后,它的全部元素會被析構(gòu),但是new出來的內(nèi)存沒有刪除,導(dǎo)致內(nèi)存泄漏//第一版本
void dosomething(){
vector<widget *>vmp;
for(int i=0;i<N;++i)vwp.push_back(new wideget);
}
...
for(vector<widget*>::iterator i=vmp.begin();i!=vmp.end();++i)delete i;
//當(dāng)時當(dāng)new 過程中出現(xiàn)異常,還是會導(dǎo)致內(nèi)存泄露//第二版本
struct DeleteObject{template<typename T>void operator()(const T *ptr){delete ptr;}
};
void dosomething(){typedef boost::shared_ptr<widget>spw;vector<spw>vmp;
for(int i=0;i<N;++i)vwp.push_back(spw(new wideget);
}
...
for_each(vmp.begin(),vmp.end(),DeleteObject());//將指針給智能指針,不怕發(fā)生異常內(nèi)存泄漏,然后采用for_each,區(qū)間比單元素需要要高

7.切勿創(chuàng)建包含auto_ptr的容器對象

首先auto_ptr的對象是被c++標(biāo)準(zhǔn)所禁止的,說明可以移植性不強。

上面提到,STL中采用的是拷貝的方法,auto_ptr對象進行拷貝時會將原來的對象所有權(quán)設(shè)置交給新對象,然后將原來對象所有權(quán)設(shè)為為NULL

例如在排序時,會將基準(zhǔn)元素拷貝給一個臨時對象,使容器中一個元素為null,臨時對象會在作用域結(jié)束后被銷毀。導(dǎo)致容器可能會失去一個或者多個對象。

8.慎重選擇刪除元素的方法

container<int>c;
  • 對于容器c,如果想刪除值為1963的元素。對于不同容器應(yīng)該采用不同的方法。

對于連續(xù)容器例如 vector,deque,string

c.earse(remove(c.begin(),c.end(),1963),c.end());

對于list

c.remove(1963);

對于關(guān)聯(lián)容器采用

c.erase(1963);
  • 當(dāng)要刪除判別式為 true的值
bool badValue(int);

對于連續(xù)容器例如 vector,deque,string

c.earse(remove_if(c.begin(),c.end(),badValue),c.end());

對于list

c.remove_if(badValue);

對于關(guān)聯(lián)容器,兩種方法

//方法一
AddocContainer<int>c;
...
AddocContainer<int>goodValues;
remove_copy_if(c.begin(),c.end(),inserter(goodValues,goodValues.end(),badValue);
//將不用刪除的元素放入goodValues容器中
//將兩容器元素交換
c.swap(goodVlues;)
//方法二
for(AddocContainer<int>::iterator i=c.begin();i!=c.end();){if(badValues(*i))c.earse(i++);  //確保i被刪除后,有一個迭代器指向下一個元素。關(guān)聯(lián)容器不反悔元素else++i;
}
//對于 vector,deque,string,list,想要在為true時,寫日志for(AddocContainer<int>::iterator i=c.begin();i!=c.end();){if(badValues(*i)){logFile<<"earse "<<*i<<"/n";i =c.earse(i);  }//確保i被刪除后,有一個迭代器指向下一個元素。序列元素返回之下下一個元素的迭代器else++i;
}             

9.了解分配子allocator的約定和限制

  • 你的分配子是一個模板,模板參數(shù)T代表你為它分配內(nèi)存對象的類型
  • 提供類型定義pointer和reference,但始終讓pointer為T* ,讓reference 為T&
  • 千萬不要讓你的分配子擁有隨對象而不同的狀態(tài)。通常分配子不應(yīng)該有非靜態(tài)的數(shù)據(jù)結(jié)構(gòu)
  • 傳給分配子的allocate成員函數(shù)的是那些要求內(nèi)存的對象的個數(shù),new傳遞的是void 需要的字節(jié)個數(shù)。同時記住,allocate返回的T*指針,既然沒有T對象被構(gòu)造。*
  • 一定也要提供嵌套的rebind模板,因為標(biāo)準(zhǔn)容器依賴該模板。

10.切勿對STL容器的線程不安全性有不切實際的依賴

STL不提供線程安全,需要自己寫互斥鎖

//定義lock類
template<tyname Container>
class Lock{
public:
Lock(const Container& container):c(container){getMutexFor(c);//創(chuàng)造互斥體
}
~Lock(){releaseMutexFor(c);//析構(gòu)互斥體
}
private:
const Container& c;
}//
vector<int>v;
...
{Lock<vector<int>>lock(v);vector<int>::iteator first5(find(v.begin(),v.end(),5));if(first5 !=v.begin())*first5=0;
}//代碼塊結(jié)束,互斥體被釋放

11.vector和string優(yōu)于動態(tài)分配的數(shù)組

vector和string可以實現(xiàn)自己釋放內(nèi)存,并且可以使用STL算法

但是在多線程情況下使用string,可能會造成性能下跌,不如使用vector,因為string采用的是引用計數(shù)。

12.使用reserve避免不必要的重新分配

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-C8FNfW2Q-1692172443245)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220911205652519.png)]

因為當(dāng)容器容量不滿足需求時,會進行容量擴充,重新申請一個是當(dāng)前容量數(shù)倍的內(nèi)存,把當(dāng)前內(nèi)存中元素移入然后將原來的內(nèi)存進行析構(gòu)。這個過程很浪費時間,因此兩種方法去避免。

  • 當(dāng)知道需要預(yù)留的空間大小使,用reserve函數(shù)提前去開辟。
  • 當(dāng)不知道時,開辟足夠大的,到最后在去除多余容量。

13.注意string實現(xiàn)的多樣性

STL對string的實現(xiàn)有不同的方式,每個方式都有不同的特點,詳情看第十五條

它們的區(qū)別主要是:

string的值可能會被引用,也可能不會被引用

string對象的大小范圍是char*的1倍到7倍

創(chuàng)建一個新字符串可能需要0次,1,2次動態(tài)分配內(nèi)存

string對象可能被共享,也可能不共享其大小和內(nèi)存信息

string可能支持,也可能不支持對單個對象的分配子

不同實現(xiàn)對內(nèi)存的最小分配有不同策略。

14.了解如何將string和vector 傳給舊的API

對于vector

//對于這個舊的API
void dosomething(const int* pInts,size_t numInts);
//vector 應(yīng)該傳遞 
vector<int>v;
dosomething(&v[0], numInts);
//也有人說傳遞 dosomething(v.begin(), numInts);
//begin()返回是一個迭代器,事實上對于vector迭代器就是指針,但是事實上迭代器不是一個指針

對于string

//對于舊的API
void dosomething(const char *pstring)
//strng 應(yīng)該傳遞
string str;
dosomething(str.c_str())
//因為string不是連續(xù)存儲的,而且string不一定是以空字符結(jié)尾的。所以string內(nèi)部有個c_str,指向字符串值的指針

15.使用‘swap技巧’去除多余的內(nèi)存

vector<int>n(100,0);
//刪除一部分元素,只留下十個元素,但是容器的容量還是100
n.erase(b.begin()+10,n.end());
//為了去除多余的容量,使用swap
vector<int>(n).swap(n);
//通過vector<int>(n)創(chuàng)建一個隱式對象,這個對象的容量大小就是n實際包含元素的大小,然后與n進行交換,再將隱式對象析構(gòu)掉。消除對于容量。
//swap調(diào)用拷貝構(gòu)造函數(shù)一次,賦值函數(shù)兩次,將兩個對象指針進行調(diào)換。不僅容器的內(nèi)容就交換了,指針,引用都被交換了(string除外),但是相對來說還是在原來的容器中。//使用swap使內(nèi)存最小
vector<int>().swap(n);
string str="dada";
string ().swap(str);

16.避免使用vector

因為vector不滿足c++標(biāo)準(zhǔn):c如果是包含對象T的容器,則 T* p=&c[0]是可以通過編譯的。但是對于vector是不行的。因為,vector在內(nèi)部是一位一位存的,而不是按自己存儲,因為沒辦法創(chuàng)建指向單個位的指針

可以用deque替代和bitset替代(大小固定,不能插入元素)。

17,理解相等和等價的區(qū)別

等價不一定是相等的,相等肯定是等價的。

對于類的等價,取決于operator = =函數(shù)中的函數(shù)體。在關(guān)聯(lián)容器中,例如map,set這種順序存儲的容器,需要定義一個比較類去確定它們的順序。

struct CIstringCompare{
public:
binary_function<string,string,bool>
bool operator()(const string&lhs,const string&rhs )const{
return ciStringCompare(lhs,rhs);//忽略string 大小寫的比較
}
};
set<string,CIstringCompare)ciss;

18.為包含指針的關(guān)聯(lián)函數(shù)指定比較類型

set<string *>ssp;
ssp.insert(new string("Anteater"));
ssp.insert(new string("Wombat"));
ssp.insert(new string("Lemur"));
ssp.insert(new string("Penguin"));
for(set<string *>::iterator it;it!=ssp.end();it++){
cout<<*it<<endl; //打印的是地址 ,而且不一定是按照字符串順序打印的,因為set是根據(jù)地址大小進行排序的
}//因此需要寫一個比較類去進行比較
struct DereferenceLess{template<typename,PtrType>bool operator()(PtrType lhs,PtrType rhs){return *lhs<*rhs;}
}
set<string*,DereferenceLess>ssp;//這樣就按照字符串順序進行打印

19.總讓比較函數(shù)在相等的情況下返回false

//例如給set<int,less_equal<int>> s;
s.insert(10);
s.insert(10);
//這會導(dǎo)致容器中出現(xiàn)兩個10,違背了set的定義,因為在比較兩個10是否等價時采用
!(10<=10)&&!(10<=10) //false 不等價 所以導(dǎo)致存了兩個10

20.切勿直接修改set 或者 multiset的鍵

所謂的鍵就是進行比較等價的內(nèi)容,因為set是按順序存儲的所以不能直接修改。而map是修改不了,因為map存儲類型是pair<const k,v>。

//但是有的sTL不支持修改set 它返回迭代器類型為 const T&,想要修改就要類型轉(zhuǎn)化,但是存在風(fēng)險
//const_cast 指向原來的引用
const_cast<employee>(*it).setTitle("dasd");
//使用static_cast則不行,它會生成一個臨時隱匿對象,修改的是這個對象
static_cast<employee>(*it).setTitle("dasd");
//相當(dāng)于
(employee(*it)).setTitle("dasd");

安全的方法就是拷貝一份元素將其修改,然后刪除原有的,再將其添加。

21.考慮用排序vector代替關(guān)聯(lián)容器

當(dāng)你的數(shù)據(jù)類型滿足三個階段時,可以考慮用排序vector代替關(guān)聯(lián)容器

  • 插入刪除階段,幾乎不查詢
  • 查找階段,幾乎不查找
  • 重組階段,將元素全部刪除再添加。

因為關(guān)聯(lián)容器底層為平衡二叉樹,一個節(jié)點?;顁oot,left,right三個地址,相比vector太空間。

22.當(dāng)效率至關(guān)重要,謹(jǐn)慎選擇opertor[] 和insert

map<int,widget>m
//在插入時使用operator[],相當(dāng)于先要構(gòu)造臨時對象然后析構(gòu)然后賦值
m[1]=1.50;
//相當(dāng)于
typedef map<int,widget>IntWidgetMap;
pair<IntWidgetMap::iterator,bool>result=m.insert(IntWidgetMap::value_type(1,widget()));
result.first->second=1.5;
//不如使用insert
m.insert(IntWidgetMap::value_type(1,50);//當(dāng)更新數(shù)據(jù)時
m[1]=51;
//用insert需要構(gòu)造,然后析構(gòu)然后賦值
m.insert(IntWidgetMap::value_type(k,v).first->second=v;

當(dāng)插入時用insert效率高,當(dāng)更新時用operator[]效率高。

23.使用distance 和advance將容器的const_iterator轉(zhuǎn)換為iterator

當(dāng)有的容器類的成員函數(shù)僅接受iterator作為參數(shù),const_iterator不能作為他們都參數(shù)。必須進行強制類型轉(zhuǎn)換。

typedef deque<int> IntDeque;
typedef IntDeque:: iterator Iter;
typedef IntDeque:: const_iterator ConstIter;
ConstIter ci;
Iter i(ci);
Iter i(const_cast<Iter>(ci));//const_iterator不能強制轉(zhuǎn)為iterator
//iterator 與const_iterator是兩個不同的類,它們之間的差距可能比string 與 double都遠
//但是對于vector 與string是可以通過的,因為它們的迭代器底層是char*//使用advance 與distance實現(xiàn)安全轉(zhuǎn)換 將ci 從const_iterator 轉(zhuǎn)為iterator
Iter i(d.begin());
advance(i,distance<ConstIter>(i,ci));//要加ConstIter 進行強制類型轉(zhuǎn)換

24.正確理解由reverse_iterator的base()成員函數(shù)所產(chǎn)生的iterator的用法

vector<int>v;
v.reserve(5);
for(int i=1;i<=5;++i){v.push_back(i);
}
vector<int>::reverse_iterator ri=find(v.rbegin(),v.rend(),3);
vector<int>::iterator i(ri.base());

執(zhí)行完上述代碼之后,該vector和相應(yīng)迭代器的狀態(tài)如下圖所示:

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-GGivqON4-1692172443245)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220915221408689.png)]

如果在reverse_iterator ri指向的位置插入新元素,只需要在ri.base()位置處插入元素就行了。

但是reverse_iterator處刪除元素的話,則需要執(zhí)行v.((++ri).base());

25.對于逐字符的輸入請考慮使用istreambuf_iterator

//將一個文本文件拷貝到string中
ifstream inputFile("interestingData.txt");
//這段代碼沒有將空白字符加載進去,因為istream_iterator使用operator>>函數(shù)完成實際的讀操作,默認operator>>函數(shù)會跳過空白字符
//如果沒有消除skipws標(biāo)志,將默認忽略空白字符
inputFile.unsetf(ios::skipws);//消除sKipws標(biāo)志位
string fileData((istream_iterator<char>(inputFile)),istream_iterator<char>());//但是拷貝速度不快,因為每一個operator>>操作 需要執(zhí)行許多額外的操作
//推薦使用istreambuf_iterator,速度快40%,它是直接從緩沖區(qū)中讀取下一個字符
ifstream inputFile("intersetingData.txt");
string fileData((istreambuf_iterator<char>(inputFile)),istreambuf_iterator<char>());
#include<iostream>
#include<random>
#include<ctime>
#include<fstream>
#include<iterator>
using namespace std;int main(){ofstream outfile;outfile.open("file.txt",ios::app);srand(time(nullptr));for(int i=0;i<1000000;++i){outfile<<rand()%26+'a';}clock_t start,stop;ifstream inputFile("file.txt");inputFile.unsetf(ios::skipws);start=clock();string fileData1((istream_iterator<char>(inputFile)),istream_iterator<char>());stop=clock();cout<<"istream花費了"<<(stop-start)<<endl;start=clock();string fileData2((istreambuf_iterator<char>(inputFile)),istreambuf_iterator<char>());stop=clock();cout<<"istreambuf花費了"<<(stop-start)<<endl;return 0;
}

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6UDM6W5Q-1692172443246)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220916223026949.png)]

26.確保目標(biāo)區(qū)間足夠大

//給一個容器后面插入元素
int transmogrify(int x);//該函數(shù)根據(jù)x生成一個新值
vector<int> values;
...//給values 里面插入新值
vector<int>results;
//給results.end()插入元素是錯誤的,因為*resultes.end()里面沒有元素
transform(values.begin(),values.end(),results.end(),transmogrify);
//應(yīng)該用back_inserter生成迭代器進行插入,返回的迭代器將被push_back調(diào)用
transform(values.begin(),values.end(),back_inserter(results),transmogrify);
//插在前面,被front_back調(diào)用 ,沒有front_back的容器不能使用,比如vector
transform(values.begin(),values.end(),front_inserter(results),transmogrify);
//如果擔(dān)心,需要重新分配空間,就需要使用 reserver
vector<int>results;
results.reverse(results.size()+values.size());
transform(values.begin(),values.end(),front_inserter(results),transmogrify);

27.了解各種和排序有關(guān)的選擇

  • 如果需要對vector,string,deque或者數(shù)組中的元素執(zhí)行一次完全排序,那么可以使用sort或者stable_sort進行
  • 如果有一個vector,string,deque或者數(shù)組,并且只需要對等價性最前面的n個元素進行排序,那么可以使用partial_sort
//將質(zhì)量最好的前n個放在widgets的最前面
partial_sort(widgets.begin(),widgets.begin()+n,widgets.end(),quealityCompare);
  • 如果有一個vector,string,deque或者數(shù)組,并且只需要只需要找個第n個位置的元素,或者需要找到等價性最前面的n個元素但有不對這n個元素進行排序,那么可以使用nth_element
//找出質(zhì)量最好的前n個元素,不用對n個元素進行排序
nth_element(widgets.begin(),widgets.begin()+n-1,widgets.end(),quealityCompare);
//找到質(zhì)量中間的元素
vector<widget>::iterator it=nth_element(widgets.begin(),widgets.begin()+widgets.size()/2,widgets.end(),quealityCompare);
  • 如果需要將一個標(biāo)準(zhǔn)序列容器的元素按照是否滿足某個特定的條件區(qū)分開,那么partition和stable_partition很合適
//找到第一個質(zhì)量比二級還差元素的位置
vector<widget>::iterator goodEnd=partition(widgets.begin(),widgets.end(),hasAcceptableQulity);
//返回第一個不滿足大于二級質(zhì)量條件的widget
  • 如果你的數(shù)據(jù)在一個list中,仍然可以使用partition和stable_partition

  • 排序算法的效率排序

partition,stable_partition,nth_element,partial_sort,sort,stable_sort.

28.如果確實需要刪除元素,則需要在remove這一類算法之后調(diào)用erase

//remove的參數(shù)是迭代器,并不知道容器的類型,無法調(diào)用容器的成員函數(shù) earse,所以用remove 容器中元素的數(shù)目并不會減少
template<<class ForwardIterator,class T>
ForwardIterator remove(ForwardIterator first,ForwardIterator last,const T&value);
//remove只是把不用刪除的元素移到區(qū)間的前部,它返回迭代器指向最后一個“不用刪除”的元素之后的元素。
remove(v.begin(),v.end(),99);

事實上并沒有將99的放在后面,后面還保留著舊值,用保留的值覆蓋掉要刪除的值

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OVd8Qqaz-1692172443246)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220917190200302.png)]

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FpdnjEKB-1692172443246)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220917190127261.png)]

//為了真的刪除空間中值,使用erase
v.erase(remove(v.begin(),v.end(),99),v.end());
//list的remove是和erase融合的
list<int>li;
li.remove(99);

remove對于包含指針的容器,再用在和erase進行連用時,記得先要釋放內(nèi)存,防止內(nèi)存泄漏。對于智能指針不用這樣做。

29.使用accumulate進行區(qū)間統(tǒng)計

//統(tǒng)計list中所有值的和
list<double> ld;
...//添加元素
double sum=accumulate(ld.begin(),id.end(),0.0);
//統(tǒng)計容器中所有字符串長度之和
string::size_type
StringLengthSum(string::size_type sumSoFar,const string& s){return sumFoFar+s.size();
}
set<string>ss;
string::size_type lengthSum=accumlate(ss.begin(),ss.end(),static_cast<string::size_type(0),stringLengthSum);//統(tǒng)計區(qū)間內(nèi)所有點的平均值
struct Point{Point(double initX,double initY):x(initX),y(initY){}double x,y;
}
class PointAverage:public binary_function<Point,Point,Point>{public:PointAverage():xSum(0),ySum(0),numPoints(0){}const Point operator()(const Point& avgSoFar,const Point &p){++numPoints;xSum+=p.x;ySUm+=p.y;return Point(xSum/numPoints,ySum/numPoints);}private:size_t numPoints;double xSum;double ySum;
}
Point avg=acculate(lp.begin(),lp.end(),Point(0,0),PointAverage());

30.遵循按值傳遞的原則來設(shè)計函數(shù)子類

對于多態(tài)的函數(shù)對象,不能使用虛函數(shù),因為參數(shù)類型是基類,而實參類型是派生類的,在傳遞的過程中會產(chǎn)生剝離問題:在對象拷貝的過程中,派生部分可能會被去掉,而僅保留基類部分。

函數(shù)對象在STL中作為參數(shù)或者返回時總是值傳遞,意味著第一:函數(shù)對象小巧,第二,函數(shù)對象是單態(tài)。

31.確保判別式是純函數(shù)

  • 判別式:是一個返回值為bool的函數(shù)。在STL中,判別式有著廣泛的用途。標(biāo)準(zhǔn)關(guān)聯(lián)容器的比較函數(shù)就是判別式,對于find_if以及各種排序算法,判別式往往也被作為參數(shù)來傳遞。
  • 純函數(shù):是指返回值僅僅依賴其參數(shù)的函數(shù)。
  • 判別類:是一個函數(shù)的子類,它的operator()函數(shù)是一個判別式。

判別式是純函數(shù)的理由:STL傳遞是按值傳遞,所以如果依賴判別式依賴外界參數(shù)可能會導(dǎo)致出錯。

32.若一個類是函數(shù)子,應(yīng)該讓它可配接

list<widget*>widgetPtrs;//一個包含Widget對象指針的list容器
bool isInteresting(const Widget* pw);//判斷某個Widget指針?biāo)笇ο笫欠褡銐蛴腥?//找第一個有趣的widget
list<Widget *>::iterator  i=find_if(widgetPtrs.begin().widgetPtrs.end(),isInteresting);
//如果想第一個不有趣的widget
list<Widget *>::iterator  i=find_if(widgetPtrs.begin().widgetPtrs.end(),not1(isInteresting);//錯誤
list<Widget *>::iterator  i=find_if(widgetPtrs.begin().widgetPtrs.end(),not1(ptr_fun(isInteresting));//正確//not1是函數(shù)配接器,ptr_fun的作用是完成類型定義
//只有提供必要類型定義的函數(shù)對象被稱為可被配接的函數(shù)對象
//提供這些類型定義最簡單的方式就是讓函數(shù)子從特定的基類繼承。
//函數(shù)子operator只有一個參數(shù)就從std::unary_function繼承
//函數(shù)子兩個參數(shù)就從std::binary_function繼承
//unary_function和binary_function是模板,不能直接繼承,需要提供類型實參
//operator一個參數(shù)繼承std::unary_function
template<typename T>
//提供operator第一個參數(shù)的類型和返回值類型
class MeetsThreshold:public std::unary_function<widget,bool>{
private:const T threshold;
public:bool operator()(const Widget&) const;
}//operator兩個參數(shù)的繼承
//當(dāng)函數(shù)子不需要任何私有成員
//提供operator第一個參數(shù)的類型,第二個參數(shù)的類型和返回值類型
//operator是帶引用和const而模板沒有,傳遞給unary_function,binary_function非指針類型需要去掉const 和 &
struct WidgetNameComapre:public std::binary_function<Widget,Widget,bool>{bool operator()(const Widgets& lhs,const widget&rhs)const;
}
//對于指針類型 則是可以
struct WidgetNameComapre:public std::binary_function<const Widget *,const Widget*,bool>{bool operator()(const Widgets* lhs,const widget* rhs)const;
}//類型定義后的子類可以直接只有函數(shù)配接器
list<widget>::reverse_iterator i=find_if(widgets.begin(),widgets.end(),not1(MeetsThreshold<int>()))s

33.理解ptr_fun,mem_fun和mem_fun_ref的由來

f(x);//f是一個非成員函數(shù)
x.f();//f是成員函數(shù),并且x是一個對象或者對象的引用
p->f();//f是成員函數(shù),并且p是一個指向?qū)ο髕的指針
void test(widget &w);
vector<widget>vw;
for_each(vw.begin(),vw.end(),test);//可以通過編譯
class widget{public:...void test();...
}
for_each(vw.begin(),vm.end(),&widget::test);//不能通過編譯
list<widget *>lpw;
for_each(lpw.begin(),plw.end(),&widget::test);//不能通過編譯
//原因 for_each算法是基于非成員函數(shù)實現(xiàn)的
//for_each算法的實現(xiàn)
template<typename InputIterator ,typename Function>
Function for_each(InputIterator begin,InputIterator end,Function f){while(begin!=end)f(*begin++);
}
//mem_fun,mem_fun_ref用來調(diào)整使能夠被成員函數(shù)使用
//mem_fun的定義
template<typename R,typename C>
mem_fun<R,C>;//C是類,R是指向成員函數(shù)的返回類型
mem_fun(R(C::*pmf)());
//mem_fun帶一個指向某個成員函數(shù)的指針參數(shù)pmf,并且返回一個mem_fun_t類型的對象。mem_fun_t是一個函數(shù)子類,它擁有該成員函數(shù)的指針,并提供operator函數(shù),在operator函數(shù)中調(diào)用通過參數(shù)傳遞進來的對象上的成員函數(shù)
for_each(lpw.begin(),lpw.end(),mem_fun(&widget::test));//可以通過編譯

34.算法調(diào)用優(yōu)于手寫的循環(huán)

  • 效率:算法通常比程序員自己寫的循環(huán)效率高
  • 正確性:自己寫的循環(huán)比使用算法更容易出錯
  • 可維護性:使用算法的代碼通常比手寫循環(huán)的代碼更加簡潔明了。

如果要做的工作有算法實現(xiàn)就用算法。但是如果使用循環(huán)很簡單,而使用算法實現(xiàn)的話卻要求使用綁定器和配接器或者要求一個單獨的函數(shù)子類,就使用循環(huán)。

35.容器的成員函數(shù)優(yōu)于同名算法

  • 成員函數(shù)往往速度很快
  • 成員函數(shù)通常和容器結(jié)合的更加緊密
set<int>s;
...  //插入一百萬個值
set<int>::iterator i=s.find(727);//以對數(shù)時間運行
if(i!+s.end())...
set<int>::iterator i=find(s.begin(),s.end(),727);//使用find算法 以線性時間運行

35.正確區(qū)分count,find,binary_search,lower_bound,upper_bound和equal_range

  • 對于區(qū)間沒有排序的,應(yīng)當(dāng)使用count和find,它們是線性時間,使用相等性查找

    vector<int>s;
    

    count是找區(qū)間中存在某個特定值的個數(shù)

    int num=count(s.begin,s.end(),5);//查找5在區(qū)間存在的個數(shù)
    

    find 是找區(qū)間中第一個特定值的位置

    int index=count(s.begin,s.end(),5);//查找第一個5的位置
    
  • 對于區(qū)間排序的,可以使用binary_search,equal_range,lower_bound,對數(shù)時間,使用等價性查找

    vector<widget>vm;
    ...
    wdiget w;
    

    binary_search,只回答是否存在的問題

    bool exist=binary_search(vm.begin(),vm.end(),w);//查看5是否存在
    

    lower_bound,返回一個迭代器,如果存在返回第一份的拷貝,如果不存在返回適合于插入該值的位置

    vector<widget>::iterator it=lower_bound(vm.begin(),vm.end(),w);
    

    equal_range,返回一對迭代器,第一個迭代器等于lower_bound返回的迭代器,第二個迭代器等于upper_bound(指向區(qū)間內(nèi)最后一個等價元素的下一個位置)返回的迭代器

    typedef vector<widget>::iterator VMIter;
    typedef pare<VMIter,VMIter> VMIterPair;
    VMIterPair p=equal_range(vm.begin(),vm.end(),w);
    //兩個迭代器之間的距離,即使原始區(qū)間查找等價對象的數(shù)目
    if(p.first!=p.second){
    //說明存在
    }
    {
    //說明不存在,兩個迭代器都指向w的插入位置
    }
    

    [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TvGCesVE-1692172443247)(C:\Users\18440\AppData\Roaming\Typora\typora-user-images\image-20220918171324230.png)]

36.避免直寫型的代碼

假如有一個vector,現(xiàn)在想刪除其中所有其值小于x的元素,但是,在最后一個其值不小于y的元素之前的所有元素應(yīng)該保留下來。

vector<int> v;
int x,y;
...
v.erase(remove_if(v.rbegin(),v.rend(),bind2nd(greater_equal<int>(),y)).base(),v.end(),bind2nd<less<int>>(),x)),v.end());
//可讀性太差,不利于后來者維護
//進行分解
typedef vector<int>::iterator VecIntIter;
//初始化rangeBegin,使它指向v中大于等于y的最后一個元素之后的元素
//如果不存在這樣的元素,則rangeBegin被初始化為v.bgein()
//如果這樣的元素正好是V最后一個元素,則rangeBegin被初始化為v.end()
VecIntIter rangeBegin=find_if(v.rbegin(),v.rend(),bind2nd(greater_equal<int>(),y)).base();
//從rangeBegin到v.end()的區(qū)間中刪除所有小于x的值
v.erase(remove_if(rangeBegin,v.end(),bin2nd(less<int>(),x)),v.end());
//bind2nd 將二元函數(shù)轉(zhuǎn)為一元函數(shù),因為函數(shù)內(nèi)一個參數(shù)已經(jīng)被確定

37.總是包含(#include)正確的頭文件

因為不同的平臺頭文件之間包含關(guān)系不通,因此任何時間如果你使用某個頭文件中的一個STL組件,一定要提供對應(yīng)的#include 指令

[外鏈圖片轉(zhuǎn)存中…(img-TvGCesVE-1692172443247)]

36.避免直寫型的代碼

假如有一個vector,現(xiàn)在想刪除其中所有其值小于x的元素,但是,在最后一個其值不小于y的元素之前的所有元素應(yīng)該保留下來。

vector<int> v;
int x,y;
...
v.erase(remove_if(v.rbegin(),v.rend(),bind2nd(greater_equal<int>(),y)).base(),v.end(),bind2nd<less<int>>(),x)),v.end());
//可讀性太差,不利于后來者維護
//進行分解
typedef vector<int>::iterator VecIntIter;
//初始化rangeBegin,使它指向v中大于等于y的最后一個元素之后的元素
//如果不存在這樣的元素,則rangeBegin被初始化為v.bgein()
//如果這樣的元素正好是V最后一個元素,則rangeBegin被初始化為v.end()
VecIntIter rangeBegin=find_if(v.rbegin(),v.rend(),bind2nd(greater_equal<int>(),y)).base();
//從rangeBegin到v.end()的區(qū)間中刪除所有小于x的值
v.erase(remove_if(rangeBegin,v.end(),bin2nd(less<int>(),x)),v.end());
//bind2nd 將二元函數(shù)轉(zhuǎn)為一元函數(shù),因為函數(shù)內(nèi)一個參數(shù)已經(jīng)被確定

37.總是包含(#include)正確的頭文件

因為不同的平臺頭文件之間包含關(guān)系不通,因此任何時間如果你使用某個頭文件中的一個STL組件,一定要提供對應(yīng)的#include 指令

在一個聲明為const的成員函數(shù)內(nèi)部,該類所有的非靜態(tài)數(shù)據(jù)成員都自動被轉(zhuǎn)換為相應(yīng)的const類型。

http://www.risenshineclean.com/news/3574.html

相關(guān)文章:

  • 網(wǎng)站建設(shè)公司創(chuàng)意軟文范例800字
  • 做民宿上幾家網(wǎng)站好廣點通推廣登錄入口
  • 鄭州專業(yè)做網(wǎng)站手機百度高級搜索入口
  • 網(wǎng)站模板怎么打開網(wǎng)絡(luò)營銷策略的內(nèi)容
  • 青島外貿(mào)網(wǎng)站建設(shè)哪家好網(wǎng)絡(luò)事件營銷
  • 福州網(wǎng)站建設(shè)方案長沙seo外包
  • 安全月考評哪個網(wǎng)站做北京網(wǎng)站建設(shè)公司案例
  • 簡單設(shè)計網(wǎng)站百度官網(wǎng)推廣
  • java做網(wǎng)站軟件太原seo關(guān)鍵詞排名優(yōu)化
  • 建立門戶網(wǎng)站的步驟網(wǎng)絡(luò)廣告投放網(wǎng)站
  • 交友網(wǎng)站app推廣今日熱點新聞15條
  • 南陽網(wǎng)站排名優(yōu)化公司企業(yè)網(wǎng)站推廣可以選擇哪些方法
  • 濱江區(qū)網(wǎng)站開發(fā)公司百度競價托管一月多少錢
  • vs中新建網(wǎng)站和新建web項目的區(qū)別電腦培訓(xùn)學(xué)校網(wǎng)站
  • 網(wǎng)站建設(shè)開發(fā)公司有哪些企業(yè)站seo報價
  • wamp 設(shè)置多個網(wǎng)站愛鏈在線
  • 網(wǎng)站設(shè)計需要考慮哪些基本原則知乎關(guān)鍵詞排名優(yōu)化
  • 如何制作手機免費網(wǎng)站模板下載排名網(wǎng)
  • 日本網(wǎng)站服務(wù)器安徽網(wǎng)站關(guān)鍵字優(yōu)化
  • 網(wǎng)站建設(shè)基礎(chǔ)策劃書做游戲推廣怎么找客戶
  • 深圳康福特戶外家具營銷型網(wǎng)站seo教程免費
  • 想做一個駕校的招生網(wǎng)站應(yīng)該怎么做seo實戰(zhàn)教程
  • 網(wǎng)站后臺密碼錯誤今天重要新聞
  • 廣西網(wǎng)站seo工具下載
  • 加國無憂51工作網(wǎng)seo顧問是干什么
  • 醫(yī)療網(wǎng)站建設(shè)焦作網(wǎng)絡(luò)推廣哪家好
  • app開發(fā)長沙seo營銷外包
  • 荊軻網(wǎng)絡(luò)做網(wǎng)站瀏覽器搜索引擎大全
  • 徐州銅山區(qū)seo模擬點擊軟件
  • 深圳服裝外貿(mào)公司廣州網(wǎng)站優(yōu)化關(guān)鍵詞排名