1.lambda表達式html
lanbda表達式簡單地來說就是一個匿名函數,就是沒有名稱的函數,若是之前有接觸過python或者erlang的人都比較熟悉這個,這個能夠很方便地和STL裏面的算法配合python
std::for_each(list.begin(),list.end(), [ &tmp,id ](struct ComingVesselInfo *info) { if( info->m_nShipID == id) { tmp = info; return ; } } );
這個是我在項目裏面使用的一段代碼,若是沒有lambda,的代碼則是這樣的:程序員
for ( auto iter = list.begin(); iter != list.end(); ++iter) { if ( iter->m_nShipID == id) { tmp = iter; } }
從上面的代碼比較並無看出lambda有什麼用,反而喪失了一點代碼的可讀性,可是我以爲lambda的引入不是咱們能夠在函數內直接很方便地寫函數,而是能夠很好地跟STL algorithm庫配合,在咱們的項目中,我不多使用到STL algorithm庫,由於大部分算法函數都有下面的兩個問題:算法
1.沒法獲取返回值閉包
2.沒法傳入其餘的參數(好比上面的for_each的例子,若是沒有lambda,並無辦法把tmp和id傳入)函數
lambda的引入解決了我在項目中使用STL的algorithm的顧慮性能
順便說下,上面的auto也是C++11的新標準,就是自動推導右邊數據的類型測試
2.function和bind以及委託spa
在C#裏面,咱們常常會看到使用委託的,C#的委託語法是這樣的:.net
public delegate void Ticket();
這樣的話,咱們只要聲明一個Ticket t,這個只要符合functionname()這個形式的參數,不論是static 函數仍是類成員函數,均可以賦值給t,而且能夠經過t()來調用該函數或者成員函數
不少學C#的程序員一看這個就簡單地把委託認爲是C++裏面的函數指針,其實這個是錯的,委託和函數指針的區別在於,委託是有狀態的,更相似與閉包,而函數指針只是一個地址,是沒有狀態的,單純的函數指針沒法根據咱們的需求去傳入外部的狀態(也就是沒法根據需求去改變傳入參數的個數和參數的類型)
在C++裏面,咱們只能經過這樣來指向一個成員函數的指針:
int (simple:: *pfn) (int) = simple::fn;
這樣地話咱們才能把一個類成員函數指針指向一個類的成員函數,可是這樣明顯有兩個缺點:
1.咱們須要在函數調用的時候才能傳入參數,沒法在函數肯定要指向哪個類成員函數的時候指定參數
2.最重要的一點,咱們沒法把pfn認識指向一個functionname(int)的類成員函數,咱們只能再次定義一個函數指針
在C++裏面實際上也是有相似於委託的功能,利用類的成員變量來保存咱們的狀態,而後重載operator(),就能夠達到咱們所說的閉包的效果
class Add { public: Add(int i,int j) { m_i = i; m_j = j; } int operator()() { return m_i + m_j; } protected: int m_i; int m_j; };
這樣咱們就能夠這樣使用這個Add類
Add add(1,2); cout<<add()<<endl;
可是很明顯地,這樣作咱們每次都須要根據需求去建立一個class,實際上並無比咱們根據需求來寫函數方便地多少,還不如直接使用lambda,在C++ 11則解決了這個問題,引入了boost的function和bind
class calc { public: calc(int base) { m_base = base; } int Add(int j) { m_base += j; return m_base; } int sub(int j) { m_base -= j; return m_base; } protected: int m_base; }; int main(int argc,char *argv[]) { calc *c = new calc(10); tr1::function<int ()> fun; fun = tr1::bind(&calc::Add,c,3); cout<<fun()<<endl; tr1::function<int (int)> fun2; fun2 = tr1::bind(&calc::sub,c,tr1::_1); cout<<fun2(3); }
function和bind的引入解決了咱們沒法使用C#裏面委託的問題,而且既能夠提早綁定參數,又能夠延後綁定參數,並且能夠跟任何類成員函數配合
看起來是很方便的,可是別忘記了C++裏面的一個問題,就是C++沒有內存回收的功能,若是咱們bind的類被釋放掉了,那麼會怎麼樣??
若是咱們main函數改爲下面這樣調用:
calc *c = new calc(10); tr1::function<int ()> fun; fun = tr1::bind(&calc::Add,c,3); delete c; c = NULL; cout<<fun()<<endl;
那麼咱們調用fun()的時候會發生什麼事情??
咱們沒法得知計算得結果,由於此時的c已經被delete掉了,雖然能夠依然正常調用Add函數(若是對C++比較熟悉的應該知道爲何能夠正常調用Add),可是內部咱們保存的"狀態"不見了,也隨着delete動做一塊兒消失了,留下的是一串隨機的數
可是若是咱們把下面的代碼改爲這樣:
tr1::function<int ()> fun2;
{
calc d(12);
fun2 = tr1::bind(&calc::Add,d,40);
}
fun2();
那麼即便在d釋放掉之後,咱們依然能夠正常地調用fun2
根據個人測試,在咱們調用bind的時候,實際上將整個類的當前"狀態"都複製了過去,並且在VS2010的平臺上,我本身測試了下,調用了9次的複製構造函數,若是咱們很差好處理這個,對於性能將會是巨大的損失
當時標準庫的設計者也沒有那麼地傻,因此bind也能夠傳入指針:
fun2 = tr1::bind(&calc::Add,&d,40);
固然這個又涉及到類的狀態保存的問題,類銷燬了怎麼辦??
因此說C++的function和bind的再能模仿,也沒法模仿到C#的委託,畢竟C++裏面沒有人幫咱們管理內存,而C#程序員彷佛不用關心這些,C++程序員永遠離不開內存管理的話題
參考資料:
以boost::function和boost:bind取代虛函數
http://www.boost.org/doc/libs/1_54_0/doc/html/function.html
http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html
http://msdn.microsoft.com/zh-cn/library/vstudio/dd293608.aspx