lambda表示式捕獲變數的生命週期
阿新 • • 發佈:2022-12-05
在C++11中,lambda表示式有兩種變數捕獲方式,分別為值捕獲和引用捕獲。這兩種捕獲的形式如下:
#include <iostream> int main(int argc, char* argv[]) { int i = 42; auto l1 = [i]() //值捕獲 { std::cout << "l1::i = " << i << std::endl; }; auto l2 = [&i]() //引用捕獲 { std::cout << "l2::i = " << i << std::endl; }; i = 1024; l1(); //42 l2(); //1024 return 0; } //g++ lambda_lifecycle.cpp -o test -std=c++11Copy
使用值傳遞時,編譯器將l1
中的i
初始化為main
函式中的i
相同的值(42),之後,l1
中的i
與main
函式中的i
不再有任何關係。使用引用傳遞時則不同,l2
中的i
為main
函式中i
的副本,兩者在記憶體中的地址是相同的。
所以,在main
函式中更改i
的值時,對l1
無任何影響,而對l2
有影響。l1
中的i
的宣告週期與main
函式中的i
沒有任何關係,l2
中的i
的宣告週期與main
函式中的i
是相同的。這也導致了一個問題:當lambda
表示式的生命週期大於main
函式i
的生命週期時,程式會產生致命錯誤。
#include <iostream> #include <thread> #include <chrono> std::thread t; void func() { int i = 42; std::cout << "address of i:" << &i << " value of i:" << i << std::endl; t = std::thread([&i](){ std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "address of i:" << &i << " value of i:" << i << std::endl; }); } int main(int argc, char* argv[]) { func(); std::this_thread::sleep_for(std::chrono::seconds(1)); t.join(); return 0; }Copy
執行結果如下:
g++ lambda_lifecycle.cpp -o test -std=c++11 -lpthread
./test
address of i:0x7fff7ab11ebc value of i:42
address of i:0x7fff7ab11ebc value of i:0Copy
當func
函式執行完成之後,變數i
所在地址被彈出棧,等待2
秒之後,執行緒t
對變數i
執行讀取操作是未定義行為。
在使用lambda
表示式捕獲變數時,永遠不要在捕獲區域性變數時使用引用捕獲。