C++ lambda函數(shù)在程序開發(fā)中作用體現(xiàn)
作為一個編程人員,在運用一個語言進行程序開發(fā)時,都想通過各種辦法來提高自己程序的性能以及提高編程效率。那么在C++語言中,又該如何操作呢?我們在這里為大家介紹的額C++ lambda函數(shù),就是一個可以使代碼性能有較大提升的函數(shù)。#t#
使編譯器以及操作系統(tǒng)從正在創(chuàng)建的應用中榨取更高性能的關鍵在于提供充足的有關代碼意圖的信息。在充分了解這個代碼意圖實現(xiàn)的功能等信息的情況下, 就有可能將代碼在編譯時和運行時的并行吞吐量最大化,令開發(fā)者可以將更多精力放在他們所關注的商業(yè)領域的問題,將重量級的多核多處理器的任務計劃交托給編 譯器,運行時庫以及操作系統(tǒng)中的基礎設施代碼來處理。
循環(huán)函數(shù)是很重要的一個環(huán)節(jié),因為在所有可用的硬件資源中,被分離的循環(huán)中的各個部分在一般情況下能夠提供更高的應用性能??紤]這樣一個小情況:迭代選定組合中的全部元素以求得總和。最簡單最直接的執(zhí)行方法如下:
- std::vector< int> v;
- v.push_back(1);
- v.push_back(5);
- int total = 0;
- for (int ix = 0; ix < v.size(); ++ix){
- total += v[ix];
- }
以上的例子十分便于人工讀寫。對于熟悉C語言家族語法的開發(fā)者而言,這個循環(huán)的意圖也十分容易理解。然而對于編譯器以及運行時庫的組合而言,要在多個線程之間計劃好這個循環(huán),它還需要類似于OpenMP編譯指示一類的指示來告訴它哪里有優(yōu)化的空間:
- std::vector< int> v;
- v.push_back(1);
- v.push_back(5);
- int total = 0;
- #pragma omp for
- for (int ix = 0; ix < v.size(); ++ix){
- #pragma omp atomic
- total += v[ix];
- }
第一個OpenMP指示提出了多線程運行for循環(huán)的要求,而第二個omp atomic指示則被用來防止多線程同時向總數(shù)變量上寫入。對于OpenMP,在MSDN庫的參考文檔中有關于所有指示的詳細介紹。
如果使用了聲明式循環(huán)技巧,那么將并行方法應用在矢量求和上則更加干凈簡單。STL for_each函數(shù)是一個理想的替代品,以上的例子則被改寫如下:
- class Adder{
- private:
- int _total;
- public:
- Adder() : _total(0) {}
- void operator ( ) ( int& i )
- {
- _total += i;
- }
- operator int ( )
- {
- return _total;
- }
- };
- void VectorAdd()
- {
- std::vector< int> v;
- v.push_back(1);
- v.push_back(5);
- int total = std::for_each(v.begin(), v.end(), Adder());
- }
這里,具體的for循環(huán)被舍棄,求矢量和的代碼變得干凈了一些;但是由于需要使用一系列運行符來定義一個類,這使得這個解決方案被大大的復雜化了。 除非代碼庫中還有大量類似的求和聲明,否則一個開發(fā)者是不會僅僅為了STL for_each的那點好處而多花費功夫去定義一個新類的。
仔細檢查這個Adder類,可以很明顯的看出其大部分內(nèi)容都僅僅是用來滿足將實例用作函數(shù)對象的調(diào)用條件的。這個類中唯一起到計算作用的僅僅是那一 行_total += i。考慮到這一點,C++ 0x提供了一個被大大簡化了的、以lambda函數(shù)方式來實現(xiàn)的語法技巧。C++ lambda函數(shù)移除了對這些搭架子代碼的需求,并允許在另外的一個聲明中定義 一個謂詞函數(shù)。由此,VectorAdd函數(shù)可以被改寫如下:
- std::vector< int> v;
- v.push_back(1);
- v.push_back(5);
- int total = 0;
- std::for_each(v.begin(), v.end(),
- [&total](int x) {total += x;}
- );
Lambda函數(shù)的語法相當直截了當。方括號中的第一個lambda元素告訴編譯器,本地變量total通過引用被捕捉(這樣的情況下最好用引用捕 捉,因為你需要矢量和的結果在for_each之后仍然有效),而lambda的第二部分則是參數(shù)列表。Lambda的最后一部分是函數(shù)的主體,這個例子 中就是將參數(shù)x的值加到變量total中去。
如果在C++ lambda函數(shù)中沒有需要捕捉的變量,或者只需要捕捉變量的一個副本,那么函數(shù)開始的方括號可以留空:
- std::for_each(v.begin(), v.end(), [](int x) {
- std::cout < < x < < std::endl;
- });
混合的捕捉方法也可以使用:
- int total = 0;
- bool displayInput = true;
- std::for_each(v.begin(), v.end(), [&total, displayInput](int x) {
- total += x;
- if (displayInput){
- std::cout < < x < < std::endl;
- }
- });
這里,變量displayInput通過副本被捕捉。Visual C++編譯器在編譯時會報錯C3491:'displayInput':一個在lambda函數(shù)內(nèi)數(shù)值被改變的變量無法在一個非可變lambda中通過數(shù)值被捕捉。
Lambda函數(shù)中還有一個值得注意的地方,就是它的返回值類型。編譯器一般會盡可能的(也是被要求的)推斷l(xiāng)ambda表達式的返回值類型,不過 對于復雜的多行表達式而言,有可能會需要確切的聲明返回值類型。返回值類型聲明通過在lambda函數(shù)參數(shù)和函數(shù)主體之間添加-﹥運行符以及需要被聲明的 返回值類型來實現(xiàn):
- std::for_each(v.begin(), v.end(),
- [&](int x)->void {total += x;});
- }
C++ lambda函數(shù)的出現(xiàn),這令聲明式編程以及使用STL運算法則變得更加簡潔。Lambda函數(shù)允許在函數(shù)主體內(nèi)的可執(zhí)行代碼字行間進行定義。在為 編譯器提供強大的優(yōu)化提示之外,Lambda函數(shù)所推崇的代碼模式可以令人更加簡單的理解哪段代碼是要實現(xiàn)怎樣的功能。Visual C++ 2010將帶來在并行處理上的顯著功能提升,而lambda函數(shù)將是具體實現(xiàn)這些提升的重要手段之一。