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 表達(dá)式,用于判斷元素是否為偶數(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 進(jìn)行輸出操作
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 表達(dá)式,該 lambda 表達(dá)式通過值捕獲了局部變量 localVar
}
int main() {
// 程序的入口函數(shù)
auto lambda = createLambda();
// 調(diào)用 createLambda 函數(shù),將返回的 lambda 表達(dá)式賦值給變量 lambda
cout << lambda();
// 調(diào)用 lambda 表達(dá)式,由于 lambda 表達(dá)式通過值捕獲了 localVar 的副本,所以可以正常輸出 42
return 0;
// 程序正常結(jié)束,返回 0
}
解決方案:
#include<iostream>
// 引入輸入輸出流庫,使得程序可以使用 std::cout 進(jìn)行輸出操作
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 表達(dá)式,該 lambda 表達(dá)式通過值捕獲了局部變量 localVar
// 值捕獲會在創(chuàng)建 lambda 表達(dá)式時復(fù)制一份 localVar 的副本,即使原變量被銷毀,副本仍然有效
}
int main() {
// 程序的入口函數(shù)
auto lambda = createLambda();
// 調(diào)用 createLambda 函數(shù),將返回的 lambda 表達(dá)式賦值給變量 lambda
cout << lambda();
// 調(diào)用 lambda 表達(dá)式,由于 lambda 表達(dá)式通過值捕獲了 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

