c++中 Lambda表達式

?Lambda優化技巧

  • 盡量使用值捕獲簡單類型

  • 避免捕獲大型對象(使用引用或智能指針)

  • 將不修改的捕獲標記為const

  • 使用初始化捕獲移動語義資源


前言

1. Lambda表達式基本語法

[捕獲列表](參數列表) mutable(可選) 異常屬性(可選) -> 返回類型(可選) {// 函數體
}

捕獲列表決定了lambda表達式可以訪問哪些外部變量以及如何訪問它們:

  • []:不捕獲任何外部變量? ? ?[=]:以值捕獲所有外部變量? ?

  • [&]:以引用捕獲所有外部變量? ? ?[var]:以值捕獲特定變量var

  • [&var]:以引用捕獲特定變量var? ? ?[=, &var]:默認以值捕獲,但var以引用捕獲

  • [&, var]:默認以引用捕獲,但var以值捕獲? ? ?[this]:捕獲當前類的this指針

int a = 1, b = 2, c = 3;auto lambda1 = [=]() { return a + b; };  // 值捕獲a和b
auto lambda2 = [&]() { c = a + b; };     // 引用捕獲a、b、c
auto lambda3 = [a, &b]() { b = a + 10; }; // 值捕獲a,引用捕獲b

返回類型推斷

當lambda體只有一條return語句時,返回類型可以自動推斷:

auto lambda = [](int x) { return x * x; };  // 返回類型推斷為int

復雜情況下需要顯式指定返回類型:

auto lambda = [](int x) -> double {if (x > 0) return 1.0 / x;else return x * x;
};

通用Lambda (C++14)

C++14引入了通用lambda,可以使用auto參數:

auto print = [](auto x) { cout << x << endl; };
print(123);    // 輸出123
print("hello"); // 輸出hello
?可變Lambda (mutable)
int counter = 0;// 沒有mutable會編譯錯誤
auto incrementer = [counter]() mutable {return ++counter; // 修改的是副本
};incrementer(); // 1
incrementer(); // 2
cout << counter; // 仍然是0

編譯錯誤:默認 lambda 的?operator()?是?const?的,不能修改按值捕獲的變量。修復方式:加?mutable?或改用引用捕獲?[&counter]

該 lambda 會被轉換為類似以下的類:

class __Lambda_Counter {
public:__Lambda_Counter(int counter) : counter(counter) {}  // 拷貝構造// mutable 移除了 operator() 的 const 限定int operator()() {return ++counter;  // 允許修改成員變量}private:int counter;  // 按值捕獲的副本
};__Lambda_Counter incrementer(counter);  // 創建閉包對象

2. Lambda表達式的完整生命周期

Lambda表達式實際上是一個編譯器生成的匿名類實例,理解這一點對掌握Lambda至關重要

int x = 10;
auto lambda = [x](int y) mutable {x += y;return x;
};// 編譯器生成的等價類
class __Lambda_10 {
public:__Lambda_10(int x) : x(x) {}int operator()(int y) {x += y;return x;}private:int x;
};__Lambda_10 lambda(5);

mutable?的作用

  1. 默認情況下,lambda 的?operator()?是?const?的,不能修改捕獲的變量加上?mutable?后,operator()?變為非?const,允許修改按值捕獲的變量(但不會影響外部的原始變量)。
  2. 捕獲方式:如果改成?[&x],則捕獲引用,修改會影響外部的?x[x]?是按值捕獲,lambda?內部存儲的是?x?的副本。調用方式lambda(5)?實際上是用?lambda.operator()(5),就像調用普通函數一樣。

2. 捕獲方式的深層細節

(1) 值捕獲的陷阱
vector<int> data{1, 2, 3};// 看似捕獲了data,實則捕獲的是data的拷貝
auto lambda = [data]() {// 這里操作的是data的副本for(auto& x : data) x *= 2;
};// 原始data未被修改
lambda();
for(auto x : data) cout << x << " "; // 輸出: 1 2 3

???????按值捕獲?[data]:Lambda 內部會生成一個?data?的完整拷貝(調用?vector?的拷貝構造函數)。修改的是副本x *= 2?操作的是 lambda 內部的副本,不影響外部的?data

你的 lambda 會被編譯器轉換為類似下面的類:

class __Lambda_Data {
public:__Lambda_Data(const vector<int>& data) : data(data) {} // 拷貝構造void operator()() {for(auto& x : data) x *= 2; // 修改的是成員變量 data}private:vector<int> data; // 按值捕獲的副本
};__Lambda_Data lambda(data); // 調用時拷貝 data
lambda();                  // 修改的是內部的 data

這樣的就使按值捕獲都會在lambda類里面拷貝一份副樣本這樣的話會導致里面實現的函數所得到的值不會改變原來的參數只會改變你拷貝構造的那一份數據

如果需要修改外部?data,需使用?引用捕獲?[&data]

(2) 引用捕獲的生命周期風險
auto createLambda() {int local = 42;return [&local]() { return local; }; // 危險!返回后local被銷毀
}auto badLambda = createLambda();
cout << badLambda(); // 未定義行為,可能崩潰或輸出垃圾值

???????local?的生命周期:僅在?createLambda()?函數執行期間有效Lambda 行為:捕獲了?local?的引用,但該引用在函數返回后失效。

(3) 初始化捕獲 (C++14)
auto ptr = make_unique<int>(10);// C++14引入的初始化捕獲
auto lambda = [p = move(ptr)]() {return *p;
};// ptr已被轉移所有權,現在為nullptr

4. 模板Lambda (C++20)

C++20引入了模板參數支持:

auto genericLambda = []<typename T>(T x, T y) {return x + y;
};cout << genericLambda(1, 2);      // 3
cout << genericLambda(1.5, 2.5);  // 4.0

這樣的話就方便函數的打印可以用來直接打印函數

std::vector<int> vi{1, 2, 3};
std::vector<double> vd{1.1, 2.2};
auto print = []<typename T>(const std::vector<T>& v) {for (const auto& x : v) std::cout << x << " ";
};
print(vi);  // 1 2 3
print(vd);  // 1.1 2.2

?常見Lambda錯誤

  • 懸空引用:Lambda生命周期長于捕獲的引用

  • 意外拷貝:捕獲大型對象未使用引用

  • mutable遺漏:需要修改值捕獲變量時

  • 類型不匹配:返回類型推斷錯誤


總結

  1. 默認選擇Lambda:除非需要參數重排/部分綁定(此時用bind)

  2. 顯式優于隱式:避免[=]/[&]全捕獲,明確列出所需變量

  3. 復雜度控制:超過5行的邏輯考慮提取為命名函數

  4. 線程安全:多線程共享Lambda時避免可變共享狀態

  5. 結合現代特性:與auto/constexpr/concept等特性協同使用

Lambda表達式重新定義了C++的函數式編程范式,合理運用可使代碼既保持高性能又提升可讀性,是現代C++開發的核心技能之一。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85868.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85868.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85868.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

睿是信息攜手Arctera,深化服務中國市場,共筑數據管理新未來

2025年6月23日&#xff0c;為了更加深入服務中國大陸地區的廣大用戶&#xff0c;上海睿是信息科技有限公司&#xff08;以下簡稱“睿是信息”&#xff09;與全球數據管理領域的領導者Arctera&#xff0c;雙方正式達成戰略合作&#xff0c;自2025年7月7日起&#xff0c;睿是信息…

【WebGIS系列】WebGIS 開發相關的資源

目錄 數據 GIS 軟件 地圖渲染庫 EPSG 相關工具 資源 以下為個人收集的與 WebGIS 開發相關的資源&#xff08;排名不分前后&#xff09;&#xff0c;歡迎補充。 數據 天地圖(opens in a new tab)國家統計局行政區劃(opens in a new tab)民政部全國行政區劃信息查詢平臺(…

【單調棧】-----【小A的柱狀圖】

小A的柱狀圖 題目鏈接 題目描述 柱狀圖是有一些寬度相等的矩形下端對齊以后橫向排列的圖形&#xff0c;但是小A的柱狀圖卻不是一個規范的柱狀圖&#xff0c;它的每個矩形下端的寬度可以是不相同的一些整數&#xff0c;分別為 a [ i ] a[i] a[i]&#xff0c;每個矩形的高度是…

MySQL 索引優化與慢查詢優化:原理與實踐

MySQL是一個廣泛使用的關系型數據庫管理系統&#xff0c;優化MySQL的性能對于保證應用的高效運行至關重要。本文將詳細介紹MySQL索引優化與慢查詢優化的原理和實踐方法。 一、MySQL索引優化 1.1 索引的基本概念 索引是一種用于提高數據庫查詢速度的數據結構。常見的索引類型…

【AS32系列MCU調試教程】應用開發:基于AS32芯片的流水燈功能實現

摘要&#xff1a; 本文以國科安芯的AS32系列MCU芯片為例&#xff0c;聚焦于基于 AS32 芯片的流水燈功能開發&#xff0c;深入闡述了開發環境搭建、工程配置以及調試等關鍵環節。通過詳盡的實驗過程與結果分析&#xff0c;旨在為相關領域技術人員提供一套系統、高效且成本可控的…

爬蟲001----介紹以及可能需要使用的技術棧

首先1??。。。全篇使用的技術棧當然是python了&#xff0c;畢竟作為一名點點點工程師&#xff0c;實際工作中做測試開發用的也是python&#xff0c;畢竟測試框架么&#xff0c;不需要什么"速度"。也會一點點cpp和js&#xff0c;但不多。什么&#xff1f;你說go和ja…

Java 中基于條件動態決定字段參與分組的實現方法

在 Java 的 Stream API 中&#xff0c;Collectors.groupingBy()方法為數據分組提供了強大的支持。通過它&#xff0c;我們可以輕松地將集合中的元素按照某個屬性進行分組&#xff0c;比如按照商品類別、日期等。然而&#xff0c;在實際業務場景中&#xff0c;有時需要根據特定條…

AppBarLayout+ CoordinatorLayout,ViewPager2為什么不會覆蓋AppBarLayout

<?xml version"1.0" encoding"utf-8"?> <layout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/tools&quo…

【群體智能優化算法系列 】一 粒子群算法 (Particle Swarm Optimization, PSO)

【群體智能優化算法系列 】一 粒子算法 一&#xff1a;前言二&#xff1a;算法原理2.1 核心思想2.2 PSO核心公式?2.3 PSO算法流程圖 三&#xff1a;python實現 二維Rastrigin函數 最低點檢索例子參考 一&#xff1a;前言 粒子群算法是由Kennedy和Eberhart在1995年提出的一種基…

Jupyter notebook調試:設置斷點運行

寫了一段小代碼&#xff0c;主要是用來測試一段序列的k均值聚類效果&#xff1b; 中間想到debug一下&#xff0c;但是想到自己似乎從來沒有正式地接觸過jupyter notebook中地debug&#xff0c;平時也只是多開幾個cell&#xff0c;然后在其他cell中復制粘貼部分代碼&#xff0c…

[12-2] BKP備份寄存器RTC實時時鐘 江協科技學習筆記(14個知識點)

1 2 3 4 5 6 7 8 RTC是“Real-Time Clock”的縮寫&#xff0c;中文意思是“實時時鐘”。這是一種在電子設備中使用的時鐘&#xff0c;它能夠提供準確的時間信息&#xff0c;即使在設備斷電的情況下也能繼續運行&#xff0c;因為它通常由一個小型電池供電。RTC廣泛應用于計算機…

優化給AI的“提問技巧”(提示工程),讓大型語言模型(比如GPT)更好地扮演“心理治療助手”的角色

優化給AI的“提問技巧”(提示工程),讓大型語言模型(比如GPT)更好地扮演“心理治療助手”的角色 尤其是在“問題解決療法”(PST)中幫助 caregivers(家庭護理者)緩解焦慮、疲勞等心理癥狀。以下是核心內容的通俗解讀: 一、研究背景:AI當心理醫生靠譜嗎? 現狀:全球…

Java的lambda表達式應用

Lambda表達式是Java 8引入的一項強大特性&#xff0c;它允許以更加簡潔的方式表示匿名函數。Lambda表達式不僅讓代碼更加簡潔、清晰&#xff0c;而且為函數式編程提供了有力支持&#xff0c;從而提升了Java語言的表達能力。 本文主要講解lambda應用stream處理集合的應用。 1、…

云原生/容器相關概念記錄

文章目錄 網絡與虛擬化技術云平臺與架構容器與編排容器網絡方案性能優化與工具硬件與協議 網絡與虛擬化技術 P4可編程網關 P4: Programming Protocol-independent Packet Processors一種基于P4語言的可編程網絡設備&#xff0c;支持自定義數據包處理邏輯。P4可編程技術詳解&am…

[C++] traits機制

文章目錄 C之type_traitsis_floating_point<T> ..的使用std::enable_if<T>::type的使用std::remove_cv 如何自定義traits C之type_traits is_floating_point …的使用 一般在定義打印模板函數的時候&#xff0c;當我們用printf進行終端日志打印&#xff0c;需要根…

OpenCV 視頻處理與保存

一、知識點 1、VideoCapture類 (1)、用于從視頻文件、攝像機或圖像序列中捕獲視頻幀。 (2)、構造函數 VideoCapture(const String & filename, int apiPreference CAP_ANY) a、filename可以是視頻文件的名稱(例如"video.avi")&#xff0c;可以是圖…

【Leetcode】字符串之二進制求和、字符串相乘

文章目錄 算法原理二進制求和題目鏈接題目描述解題思路代碼 字符串相乘題目鏈接題目描述解題思路代碼 算法原理 這兩道題都是屬于算法里一種經典題型&#xff1a;高精度加/減/乘/除法&#xff0c;需要我們模擬加/減/乘/除 列豎式運算。 二進制求和 題目鏈接 題目鏈接 題目描…

MongoDB:索引

目錄 1、索引數據結構&#xff1a;B-樹 2、索引類型 2.1 單字段索引 2.2 復合索引&#xff08;最重要&#xff01;&#xff09; 2.3 多鍵索引&#xff08;數組字段&#xff09; 2.4 地理空間索引 2.5 全文索引 2.6 哈希索引&#xff08;分片專用&#xff09; 2.7 TTL …

【大模型】Transformer架構完全解讀:從“盲人摸象“到“通曉萬物“的AI進化論

&#x1f916; Transformer架構完全解讀&#xff1a;從"盲人摸象"到"通曉萬物"的AI進化論 —— 一位大模型探索者的技術日記 ? 第一章&#xff1a;為什么說Transformer是AI界的"蒸汽機革命"&#xff1f; 1.1 從RNN到Transformer&#xff1a;…

JavaEE:使用JMeter進行接口并發測試

一、下載與安裝&#xff1a; 1.下載apache-jmeter-5.6.3.zip&#xff1a; https://jmeter.apache.org/download_jmeter.cgi 2.解壓到D:\Program Files\apache-jmeter-5.6.3目錄 3.添加JDK環境配置到D:\Program Files\apache-jmeter-5.6.3\bin\jmeter.bat文件開頭&#xff1…