C++如何向Lambda傳遞參數(shù)與捕獲
介紹向Lambda傳遞參數(shù)與捕獲列表相關(guān)內(nèi)容
?一、向Lambda傳遞參數(shù)
?核心規(guī)則
Lambda的參數(shù)傳遞機制與普通函數(shù)類似,但有以下嚴(yán)格限制:
- ?無默認(rèn)參數(shù):Lambda不支持默認(rèn)參數(shù),必須顯式傳遞所有參數(shù)。
- ?參數(shù)嚴(yán)格匹配:實參與形參的數(shù)量、類型必須完全一致。 ?
示例1:Lambda替代isShorter
函數(shù)
// 原比較函數(shù) bool isShorter(const string &a, const string &b) { return a.size() < b.size(); } // 用Lambda實現(xiàn)相同功能 vector<string> words = {"apple", "banana", "cherry", "date"}; stable_sort(words.begin(), words.end(), [](const string &a, const string &b) { return a.size() < b.size(); });
關(guān)鍵點:
- Lambda形參
a
和b
的類型必須與容器元素類型一致(此處為const string&
)。 stable_sort
每次比較時會自動傳遞兩個元素給Lambda。
?二、捕獲列表:訪問外部變量的橋梁
?捕獲的本質(zhì)
Lambda通過捕獲列表訪問所在函數(shù)的局部變量,而非全局變量或靜態(tài)變量。
- ?按值捕獲:創(chuàng)建變量的副本,Lambda內(nèi)部修改不影響外部變量。?
- 按引用捕獲:直接操作外部變量,需注意變量生命周期。 ?
示例2:捕獲局部變量實現(xiàn)條件篩選
#include <vector> #include <string> #include <algorithm> // 過濾字符串向量,找到第一個長度大于或等于指定大小的字符串 std::vector<std::string>::const_iterator filterWords(const std::vector<std::string> &words, size_t sz) { // 捕獲 sz,按值傳遞(隱式拷貝),用于查找第一個長度 >= sz 的字符串 auto it = std::find_if(words.begin(), words.end(), [sz](const std::string &s) { return s.size() >= sz; }); return it; // 返回找到的字符串的迭代器 } int main() { std::vector<std::string> words = {"apple", "banana", "cherry", "date"}; size_t sz = 6; auto result = filterWords(words, sz); if (result != words.end()) { std::cout << "找到第一個長度 >= " << sz << " 的字符串: " << *result << std::endl; } else { std::cout << "未找到長度 >= " << sz << " 的字符串。" << std::endl; } return 0; }
關(guān)鍵點:
sz
是filterWords
函數(shù)的局部變量,必須顯式捕獲才能被Lambda使用。- 此處按值捕獲
sz
,Lambda內(nèi)部使用的是捕獲時的副本。
?三、捕獲方式詳解
?1. 顯式捕獲(Explicit Capture)?
明確指定要捕獲的變量及方式:
- ?按值捕獲:
[var]
? - 按引用捕獲:
[&var]
?
示例3:按引用捕獲動態(tài)更新值
#include <iostream> #include <vector> #include <algorithm> /** * @brief 主函數(shù),程序的入口點。 * * 該函數(shù)創(chuàng)建一個整數(shù)向量,使用 std::count_if 統(tǒng)計向量中偶數(shù)的數(shù)量,并輸出結(jié)果。 * * @return int 程序的退出狀態(tài)碼,0 表示正常退出。 */ int main() { // 定義一個整數(shù)向量 nums,并初始化其元素 std::vector<int> nums = {1, 2, 3, 4}; // 定義一個變量 count,用于存儲偶數(shù)的數(shù)量,初始化為 0 int count = 0; // 使用 std::count_if 統(tǒng)計向量中偶數(shù)的數(shù)量 // std::count_if 接受三個參數(shù):向量的起始迭代器、結(jié)束迭代器和一個謂詞函數(shù) // 謂詞函數(shù)是一個 lambda 表達式,用于判斷元素是否為偶數(shù) count = std::count_if(nums.begin(), nums.end(), [&count](int x) { // 判斷元素 x 是否為偶數(shù) return x % 2 == 0; }); // 輸出偶數(shù)的數(shù)量 std::cout << count << std::endl; // 輸出2(統(tǒng)計偶數(shù)的數(shù)量) // 返回 0 表示程序正常結(jié)束 return 0; }
關(guān)鍵點:
- 使用
&count
按引用捕獲,Lambda內(nèi)部修改會影響外部變量。 - 若
count
在Lambda調(diào)用前被銷毀(如局部變量),會導(dǎo)致懸空引用。
?2. 隱式捕獲(Implicit Capture)?
通過[=]
或[&]
批量捕獲變量:
[=]
:按值捕獲所有外部變量。[&]
:按引用捕獲所有外部變量。
?示例4:隱式捕獲簡化代碼
int threshold = 5; vector<int> data = {3, 7, 2, 8}; // 隱式按值捕獲所有外部變量(此處只有threshold) auto result = count_if(data.begin(), data.end(), [=](int x) { return x > threshold; }); cout << result; // 輸出2(7和8大于5)
?3. 混合捕獲(Mixed Capture)?
結(jié)合顯式和隱式捕獲,但需注意優(yōu)先級:
[=, &var]
:按值捕獲所有變量,但var
按引用捕獲。[&, var]
:按引用捕獲所有變量,但var
按值捕獲。
?示例5:混合捕獲實現(xiàn)靈活訪問
int base = 10; double factor = 1.5; vector<int> values = {3, 5, 7}; // 按引用捕獲base,按值捕獲其他變量 for_each(values.begin(), values.end(), [&base, factor](int &x) { x = base + x * factor; }); // 結(jié)果:base=10 → 10+3 * 1.5=14.5 → 轉(zhuǎn)為int為14 // 最終values變?yōu)閇14, 17, 20]
?四、捕獲的陷阱與解決方案
?陷阱1:懸空引用(Dangling Reference)?
當(dāng)Lambda捕獲的引用變量在調(diào)用前被銷毀時,引發(fā)未定義行為。
#include<iostream> // 引入輸入輸出流庫,使得程序可以使用 std::cout 進行輸出操作 using namespace std; // 使用標(biāo)準(zhǔn)命名空間,這樣可以直接使用標(biāo)準(zhǔn)庫中的對象和函數(shù),而無需加 std:: 前綴 auto createLambda() { // 定義一個函數(shù) createLambda,使用 auto 讓編譯器自動推導(dǎo)返回類型 int localVar = 42; // 在函數(shù)內(nèi)部定義一個局部變量 localVar,并初始化為 42 return [&localVar] { return localVar; }; // 返回一個 lambda 表達式,該 lambda 表達式通過值捕獲了局部變量 localVar } int main() { // 程序的入口函數(shù) auto lambda = createLambda(); // 調(diào)用 createLambda 函數(shù),將返回的 lambda 表達式賦值給變量 lambda cout << lambda(); // 調(diào)用 lambda 表達式,由于 lambda 表達式通過值捕獲了 localVar 的副本,所以可以正常輸出 42 return 0; // 程序正常結(jié)束,返回 0 }
解決方案:
#include<iostream> // 引入輸入輸出流庫,使得程序可以使用 std::cout 進行輸出操作 using namespace std; // 使用標(biāo)準(zhǔn)命名空間,這樣可以直接使用標(biāo)準(zhǔn)庫中的對象和函數(shù),而無需加 std:: 前綴 auto createLambda() { // 定義一個函數(shù) createLambda,使用 auto 讓編譯器自動推導(dǎo)返回類型 int localVar = 42; // 在函數(shù)內(nèi)部定義一個局部變量 localVar,并初始化為 42 return [localVar] { return localVar; }; // 返回一個 lambda 表達式,該 lambda 表達式通過值捕獲了局部變量 localVar // 值捕獲會在創(chuàng)建 lambda 表達式時復(fù)制一份 localVar 的副本,即使原變量被銷毀,副本仍然有效 } int main() { // 程序的入口函數(shù) auto lambda = createLambda(); // 調(diào)用 createLambda 函數(shù),將返回的 lambda 表達式賦值給變量 lambda cout << lambda(); // 調(diào)用 lambda 表達式,由于 lambda 表達式通過值捕獲了 localVar 的副本,所以可以正常輸出 42 return 0; // 程序正常結(jié)束,返回 0 }
?陷阱2:修改按值捕獲的變量
默認(rèn)情況下,按值捕獲的變量在Lambda內(nèi)不可修改。
int x = 10; auto lambda = [x] { x++; // 編譯錯誤:按值捕獲的變量不可修改 };
解決方案:使用mutable
關(guān)鍵字允許修改副本。
auto lambda = [x]() mutable { x++; // 修改的是副本,不影響外部x };
?陷阱3:捕獲this
指針(類成員訪問)?
在類成員函數(shù)中,Lambda需捕獲this
才能訪問成員變量。
class Processor { private: int offset; public: void process(vector<int> &data) { for_each(data.begin(), data.end(), [this](int &x) { x += offset; }); // 正確捕獲this } };
五、捕獲與參數(shù)傳遞對比
?特性 | ?參數(shù)傳遞 | ?捕獲列表 |
---|---|---|
?數(shù)據(jù)來源 | 調(diào)用時傳入的實參 | 所在函數(shù)的局部變量 |
?生命周期 | 由調(diào)用者管理 | 按值捕獲:與Lambda生命周期一致; 按引用捕獲:依賴原變量生命周期 |
?修改權(quán)限 | 形參可修改(除非聲明為const ) | 按值捕獲:需mutable ;按引用捕獲:直接修改原變量 |
?典型場景 | 比較、轉(zhuǎn)換等需要動態(tài)數(shù)據(jù)的場景 | 條件篩選、狀態(tài)保持等需要外部變量的場景 |
?六、小結(jié)
- ?參數(shù)傳遞:用于Lambda處理動態(tài)輸入數(shù)據(jù),需嚴(yán)格匹配類型和數(shù)量。?
- 捕獲列表: 按值捕獲(
[var]
):適合只讀訪問或需要副本的場景。 - 按引用捕獲(
[&var]
):適合需要修改外部變量或避免拷貝的場景,但需警惕懸空引用。 - 混合捕獲(
[=, &var]
):靈活平衡性能與安全性。 ?
- 捕獲列表: 按值捕獲(
- 核心準(zhǔn)則:優(yōu)先最小化捕獲范圍,避免隱式捕獲(如
[=]
或[&]
),顯式聲明更安全。
到此這篇關(guān)于C++如何向Lambda傳遞參數(shù)與捕獲的文章就介紹到這了,更多相關(guān)C++ Lambda傳遞參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中與輸入相關(guān)的istream類成員函數(shù)簡介
這篇文章主要介紹了C++中與輸入相關(guān)的istream類成員函數(shù)簡介,包括eof函數(shù)和peek函數(shù)以及putback函數(shù)還有ignore函數(shù),需要的朋友可以參考下2015-09-09