c/c++ lambda 表達式 剖析


lambda 表達式 剖析

## 大前提:捕獲列表里變量的確定時機。

捕獲列表和參數列表有區別,捕獲列表里的變量,是在捕獲的時間點就確定了,而不是在lambda調用時確定,參數列表是在調用時才確定。所以當捕獲了一個int i,i=12,然后在lambda后面的代碼又改變i為22,但是當調用lambda的時候,i值還是12。

## 剖析點:

1,值捕獲,即使在lambda后面改變了該值,在調用lambda時,這個值還是捕獲時的值。

2,引用捕獲,在lambda后面改變了該值,在調用lambda時,這個值不是捕獲時的值,而是改變后的值。

3,隱式捕獲:

  • [=]代表全部采用值捕獲
  • [&]代表全部采用引用捕獲
  • [=, &val]代表val為引用捕獲,其余為值捕獲
  • [&,val]代表val為值捕獲,其余為引用捕獲

4,可變lambda,當想在lambda函數體里,修改一個值捕獲的變量是,需要mutable關鍵字。

5,lambda的返回類型,函數體是單一的return語句的話,可以在聲明lambda時,省略返回值的類型。

### 由剖析點2:引用捕獲,會引發很多血案。比如,被捕獲的引用或者指針指向的對象已經不存在了,然后調用lambda時,就會出現致命錯誤。

警告:當以引用或者指針方式捕獲一個變量時,必須保證在lambda執行時變量是存在的。

建議:

1,捕獲一個普通變量時,如int, string或其他非指針類型,通常可以采用簡單的值捕獲方式。所以,只需關注變量在捕獲時,值是否是所需的值就行。

2,如果捕獲一個指針或迭代器,或引用,就必須保證在lambda被執行的時候,綁定到迭代器,指針或引用的對象仍然存在,而且,需要保證對象是預期的值。因為,有可能在捕獲的時候,是預期的值,但是在執行lambda之前有代碼改變了綁定對象的值,在執行lambda時,就變成不是預期的值了。

3,一般來說,盡量減少捕獲的數據量,來避免潛在的捕獲導致的問題。而且,如果可能的話,盡量避免捕獲指針或引用。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){
  //test1 值捕獲                                                                
  /*                                                                            
  int i = 1;                                                                    
  auto f = [i]{return i;};                                                      
  i = 10;                                                                       
  int j = f();                                                                  
  cout << j << endl;                                                            
  */

  //test2 引用捕獲                                                              
  /*                                                                            
  int i = 1;                                                                    
  auto f = [&i]{return i;};                                                     
  i = 10;                                                                       
  int j = f();                                                                  
  cout << j << endl;//3                                                         
  */

  //test3 隱式值捕獲                                                            
  /*                                                                            
  int i = 1;                                                                    
  int j = 2;                                                                    
  auto f = [=]{return i + j;};                                                  
  i = 3;                                                                        
  int m = f();                                                                  
  cout << m << endl;                                                            
  */

  //test4 隱式引用捕獲                                                          
  /*                                                                            
  int i = 1;                                                                    
  int j = 2;                                                                    
  auto f = [&]{return i + j;};                                                  
  i = 3;                                                                        
  int m = f();                                                                  
  cout << m << endl;//5                                                         
  */

  //test5 隱式,顯式混合1                                                       
  /*                                                                            
  int i = 1;                                                                    
  int j = 2;                                                                    
  //i為值捕獲,j為引用捕獲                                                      
  auto f = [=,&j]{return i + j;};                                               
  i = 3;                                                                        
  int m = f();                                                                  
  cout << m << endl;//3                                                         
  */

  //test5 隱式,顯式混合2                                                       
  /*                                                                            
  int i = 1;                                                                    
  int j = 2;                                                                    
  //i為引用捕獲,j為值捕獲                                                      
  auto f = [&,j]{return i + j;};                                                
  i = 3;                                                                        
  int m = f();                                                                  
  cout << m << endl;//5                                                         
  */

  //test6 可變lambda                                                            
  /*                                                                            
  int i = 10;                                                                   
  auto f = [i] () mutable{return ++i;};                                         
  int j = f();                                                                  
  cout << j << endl;                                                            
  */
  /*                                                                            
  const int i = 10;                                                             
  //編譯錯誤,因為i為const                                                      
  auto f = [i] () mutable{return ++i;};                                         
  int j = f();                                                                  
  cout << j << endl;                                                            
  */

  //test7 lambda的返回類型                                                      
  vector<int> ivec{-12,2,-22,3,0};
  //改變ivec里的值,負數變成整數                                                
  //此lambda不寫返回類型沒有問題.                                               
  //transform(ivec.begin(),ivec.end(),ivec.begin(),                             
  //        [](int i){return i < 0 ? -i : i;});                                 
  //此lambda不寫返回類型也沒有問題.                                             
  transform(ivec.begin(),ivec.end(),ivec.begin(),
            [](int i){if(i < 0) return -i;
              else return i;});
  for(const auto &s : ivec){
    cout << s << " ";
  }
  cout << endl;
}

c/c++ 學習互助QQ群:877684253

本人微信:xiaoshitou5854


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM