欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ lambda 匿名函數(shù)深入解析

 更新時間:2025年09月19日 08:58:59   作者:xclic  
C++11引入的lambda匿名函數(shù)(Lambda Expression)是一種輕量級的函數(shù)對象,可在需要函數(shù)的地方直接定義,無需單獨(dú)聲明,極大簡化了代碼編寫,本文給大家介紹C++ lambda 匿名函數(shù)的相關(guān)知識,感興趣的朋友一起看看吧

1、基本介紹

C++11 引入的 lambda 匿名函數(shù)(Lambda Expression)是一種輕量級的函數(shù)對象,可在需要函數(shù)的地方直接定義,無需單獨(dú)聲明,極大簡化了代碼編寫(尤其是回調(diào)函數(shù)、算法謂詞等場景)。

基本語法:

[capture-list] (parameter-list) mutable noexcept(optional) -> return-type { function-body }
組成部分說明
capture-list捕獲列表:指定如何捕獲 lambda 所在作用域的局部變量(值捕獲、引用捕獲等),不可省略。
parameter-list參數(shù)列表:與普通函數(shù)的參數(shù)列表一致(可省略,若無形參)。
mutable可選關(guān)鍵字:允許在 lambda 內(nèi)部修改值捕獲的變量(默認(rèn)值捕獲變量為 const)。
noexcept可選:指定 lambda 是否可能拋出異常(C++11 起)。
-> return-type返回類型可選,若函數(shù)體僅有一條 return 語句,編譯器可自動推導(dǎo)返回類型。
function-body函數(shù)體:lambda 的執(zhí)行邏輯。

簡單的例子

#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
    // 使用 Lambda 表達(dá)式作為 std::sort 的比較準(zhǔn)則
    // 按降序排序
    std::sort(v.begin(), v.end(), 
              [](int a, int b) { return a > b; } // Lambda 表達(dá)式
             );
    for (int i : v) {
        std::cout << i << " ";
    }
    // 輸出: 9 6 5 4 3 2 1 1
    return 0;
}

2、捕獲列表

捕獲列表定義了 Lambda 表達(dá)式如何從其所在的作用域中訪問外部變量。

2.1 值捕獲

將外部變量的值拷貝到 Lambda 中。Lambda 內(nèi)部修改不會影響外部變量。

int main() {
    int x = 10;
    int y = 20;
    // 值捕獲:將 x 和 y 的當(dāng)前值拷貝到 Lambda 中
    auto lambda_val = [x, y]() { 
        std::cout << "Inside lambda (by value): " << x << ", " << y << std::endl;
        // x++; // 錯誤!默認(rèn)情況下,值捕獲的變量是 const 的。
    };
    x = y = 100; // 修改外部變量
    lambda_val(); // 調(diào)用 Lambda
    // 輸出: Inside lambda (by value): 10, 20
    return 0;
}

2.2 引用捕獲

捕獲外部變量的引用。Lambda 內(nèi)部修改會直接影響外部變量。

int main() {
    int x = 10;
    int y = 20;
    // 引用捕獲:捕獲 x 和 y 的引用
    auto lambda_ref = [&x, &y]() { 
        std::cout << "Inside lambda (by ref): " << x << ", " << y << std::endl;
        x++; y++; // 修改會影響外部變量
    };
    lambda_ref(); // 調(diào)用 Lambda
    std::cout << "After lambda: " << x << ", " << y << std::endl;
    // 輸出: 
    // Inside lambda (by ref): 10, 20
    // After lambda: 11, 21
    return 0;
}

2.3 隱式捕獲

讓編譯器根據(jù) Lambda 體內(nèi)的代碼自動推斷需要捕獲哪些變量。

  • [=]:以值捕獲的方式捕獲所有使用到的外部變量。
  • [&]:以引用捕獲的方式捕獲所有使用到的外部變量。
int a = 1, b = 2, c = 3;
// 隱式值捕獲:自動捕獲所有使用到的外部變量 (a, b)
auto lambda1 = [=]() { std::cout << a + b << std::endl; }; 
// 注意:c 沒有被使用,所以不會被捕獲
// 隱式引用捕獲:自動捕獲所有使用到的外部變量 (a, c)
auto lambda2 = [&]() { std::cout << a + c << std::endl; c = 100; }; 

注意:應(yīng)謹(jǐn)慎使用隱式捕獲,尤其是 [&],因為它可能讓你無意中修改外部變量或引入懸空引用。

2.4 混合捕獲

int a = 1, b = 2, c = 3, d = 4;
// a 顯式值捕獲,b 顯式引用捕獲,其他使用到的變量按值捕獲(但這里沒有其他變量了)
auto lambda1 = [=, &b]() { /* a by value, b by ref */ };
// a 顯式引用捕獲,b 顯式值捕獲,其他使用到的變量按引用捕獲(但這里沒有其他變量了)
auto lambda2 = [&, b]() { /* a by ref, b by value */ };
// 錯誤!不能混合相同的捕獲模式: [=, a] 或 [&, &b]

2.5 捕獲 this 指針

在類的成員函數(shù)中,Lambda 可以通過值 [this] 或引用 [&] 捕獲 this 指針,從而訪問類的成員變量和函數(shù)。

class MyClass {
public:
    void doSomething() {
        // 捕獲 this,從而可以訪問成員變量 value
        auto lambda = [this]() { 
            std::cout << "Value: " << value << std::endl; 
            memberFunction(); 
        };
        lambda();
    }
private:
    int value = 42;
    void memberFunction() { std::cout << "Member func called\n"; }
};

2.6 初始化捕獲(C++14)

允許在捕獲時初始化變量(類似變量聲明),解決 “移動捕獲” 等場景

#include <vector>
#include <utility>  // for std::move
int main() {
    vector<int> v = {1, 2, 3};
    // 初始化捕獲:將v移動到lambda內(nèi)部的vec(避免拷貝大容器)
    auto func = [vec = move(v)] { 
        cout << "vec size: " << vec.size() << endl; 
    };
    func();  // 輸出:vec size: 3
    // cout << v.size() << endl;  // 錯誤:v已被移動,處于無效狀態(tài)
    return 0;
}

3、mutable 關(guān)鍵字

默認(rèn)情況下,對于值捕獲的變量,Lambda 的 operator() 是 const 的,這意味著你不能在 Lambda 體內(nèi)修改這些拷貝。
使用 mutable 關(guān)鍵字可以移除這個 const 限制。

int main() {
    int count = 0;
    // 沒有 mutable: 錯誤!不能修改值捕獲的變量。
    // auto lambda = [count]() { count++; }; 
    // 使用 mutable
    auto lambda = [count]() mutable { 
        count++; // 現(xiàn)在可以修改了
        std::cout << "Count inside lambda: " << count << std::endl;
    };
    lambda(); // 輸出: Count inside lambda: 1
    lambda(); // 輸出: Count inside lambda: 2
    std::cout << "Count outside: " << count << std::endl; // 輸出: Count outside: 0
    // 注意:修改的是 Lambda 內(nèi)部的副本,不影響外部變量。
    return 0;
}

重要mutable 允許你修改的是 Lambda 內(nèi)部副本的值,對外部變量毫無影響。引用捕獲不需要 mutable。

4、返回類型

編譯器通??梢宰詣油茖?dǎo) Lambda 的返回類型。但如果函數(shù)體中有多個返回語句且類型不同,或者你想要更明確的代碼,可以顯式指定。

std::vector<int> numbers = {1, 2, 3, 4, 5};
// 編譯器自動推導(dǎo)返回類型為 bool
auto is_even = [](int n) { return n % 2 == 0; };
// 顯式指定返回類型為 double (使用尾置返回類型語法)
auto divide = [](int a, int b) -> double {
    if (b == 0) {
        return 0.0; // 返回 double
    }
    return static_cast<double>(a) / b; // 返回 double
};

5、常見用法與示例

5.1 與 STL 算法結(jié)合

std::vector<int> vec = {5, 3, 8, 1, 9};
// 計算大于 5 的元素數(shù)量
int count = std::count_if(vec.begin(), vec.end(), 
                         [](int n) { return n > 5; });
// 將所有元素翻倍
std::for_each(vec.begin(), vec.end(), 
             [](int& n) { n *= 2; }); // 注意:需要引用才能修改原值
vector<int> nums = {3, 1, 4, 1, 5, 9};
// 用lambda作為sort的比較函數(shù)(降序排序)
sort(nums.begin(), nums.end(), [](int a, int b) { 
    return a > b; 
});  // nums變?yōu)椋?,5,4,3,1,1
// 用lambda作為find_if的條件(查找偶數(shù))
auto it = find_if(nums.begin(), nums.end(), [](int x) { 
    return x % 2 == 0; 
});
if (it != nums.end()) {
    cout << "找到偶數(shù):" << *it << endl;  // 輸出:4
}

5.2 并發(fā)編程中的任務(wù)

線程或異步任務(wù)(std::threadstd::async)需要執(zhí)行函數(shù),lambda 可直接定義任務(wù)邏輯

#include <thread>
#include <future>
int main() {
    // 線程任務(wù)用lambda定義
    thread t([] { 
        cout << "線程執(zhí)行中..." << endl; 
    });
    t.join();
    // 異步任務(wù)用lambda定義
    future<int> fut = async([] { 
        return 1 + 2; 
    });
    cout << "異步結(jié)果:" << fut.get() << endl;  // 輸出:3
    return 0;
}

5.3 自定義比較器

std::map<std::string, int> name_age;
// 按值(年齡)排序,而不是鍵(名字)
std::vector<std::pair<std::string, int>> vec(name_age.begin(), name_age.end());
std::sort(vec.begin(), vec.end(),
         [](const auto& a, const auto& b) { return a.second < b.second; });

6、常見問題

1. Lambda 表達(dá)式中的捕獲列表 [=] 和 [&] 有什么區(qū)別?[=] 表示隱式值捕獲,Lambda 體內(nèi)使用的所有外部變量都會將其當(dāng)前值拷貝一份到 Lambda 對象中。[&] 表示隱式引用捕獲,Lambda 體內(nèi)使用的所有外部變量都會以其引用被捕獲,在 Lambda 內(nèi)部修改它們會影響外部變量。應(yīng)謹(jǐn)慎使用 [&],以免造成意外的副作用或懸空引用。

2. 什么是“初始化捕獲”(Init Capture)?它解決什么問題?初始化捕獲(C++14)允許在捕獲列表中直接初始化一個新的成員變量。它主要解決了移動捕獲的問題。例如,你不能用普通捕獲移動一個 std::unique_ptr(因為無法拷貝),但可以用 [p = std::move(unique_ptr)] 將其所有權(quán)移動到 Lambda 內(nèi)部。它也允許你以任意表達(dá)式初始化捕獲的變量。

3. mutable 關(guān)鍵字在 Lambda 中起什么作用?默認(rèn)情況下,對于值捕獲的變量,Lambda 的函數(shù)調(diào)用運(yùn)算符 (operator()) 是 const 的,這意味著你不能修改這些捕獲的副本。mutable 關(guān)鍵字移除了這個 const 限制,允許你修改 Lambda 內(nèi)部的值捕獲變量。需要注意的是,這修改的只是副本,不影響外部原始變量。

4. Lambda 表達(dá)式的類型是什么?如何存儲或傳遞一個 Lambda?每個 Lambda 表達(dá)式都會生成一個唯一的、編譯器生成的、未命名的類型(閉包類型)。存儲和傳遞它的最佳方式是:

  • 使用 auto 進(jìn)行初始化(auto lambda = [...](){...};)。
  • 使用 std::function(如 std::function<void()>),這會帶來一些類型擦除的開銷,但非常靈活。
  • 在模板中使用(template<typename F> void foo(F func)),這是零開銷的方式。

5. 在類的成員函數(shù)中,Lambda 如何訪問類的成員變量?需要通過捕獲 this 指針。使用 [this] 或 [&](隱式捕獲)可以捕獲當(dāng)前對象的 this 指針,從而在 Lambda 內(nèi)部訪問類的成員變量和成員函數(shù)。需要注意的是,如果 Lambda 的生命周期可能比對象更長(例如,被放入一個全局隊列),這會導(dǎo)致懸空 this 指針。C++17 的 [\*this] 可以按值捕獲整個對象的副本,避免這個問題。

到此這篇關(guān)于C++ lambda 匿名函數(shù)深入解析的文章就介紹到這了,更多相關(guān)C++ lambda 匿名函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文了解什么是CDN及實現(xiàn)原理

    一文了解什么是CDN及實現(xiàn)原理

    這篇文章主要為大家介紹了什么是CDN及實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • TortoiseSVN忽略(Global?ignore)提交文件設(shè)定方式

    TortoiseSVN忽略(Global?ignore)提交文件設(shè)定方式

    文章介紹兩種SVN忽略雜碎文件的方法:本地配置忽略規(guī)則(修改config文件中的global-ignores參數(shù))和服務(wù)器端設(shè)置(通過svn:ignore屬性),方法一適合個人,方法二需管理員權(quán)限,均需注意空格格式避免報錯
    2025-08-08
  • Memcached簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    Memcached簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Memcached簡介,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • 在mac上安裝虛擬機(jī)搭載Windows服務(wù)的方法

    在mac上安裝虛擬機(jī)搭載Windows服務(wù)的方法

    這篇文章主要介紹了在mac上安裝虛擬機(jī)搭載Windows服務(wù)的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • 網(wǎng)站數(shù)據(jù)自動備份方法

    網(wǎng)站數(shù)據(jù)自動備份方法

    本文是根據(jù)作者自己多年的維護(hù)經(jīng)驗,來和大家分享下網(wǎng)站數(shù)據(jù)自動備份的一些經(jīng)驗。
    2010-04-04
  • curl.exe安裝使用的最全參數(shù)詳解以及常用命令匯總

    curl.exe安裝使用的最全參數(shù)詳解以及常用命令匯總

    Curl是一個功能強(qiáng)大的命令行工具,可以看做是命令行瀏覽器,用于與服務(wù)器進(jìn)行數(shù)據(jù)交互,支持多種數(shù)據(jù)傳輸協(xié)議,如HTTP、HTTPS、FTP等,它支持文件的上傳和下載,它是一款開源軟件,在多個操作系統(tǒng)上均可運(yùn)行,包括Windows、Linux、macOS等
    2024-04-04
  • Memcache緩存系統(tǒng)知識點(diǎn)梳理

    Memcache緩存系統(tǒng)知識點(diǎn)梳理

    Memcached是一個免費(fèi)開源的,高性能的,具有分布式對象的緩存系統(tǒng),它可以用來保存一些經(jīng)常存取的對象或數(shù)據(jù),保存的數(shù)據(jù)像一張巨大的HASH表,該表以Key-value對的方式存在內(nèi)存中
    2012-09-09
  • 華為服務(wù)器RAID陣列卡配置教程 SR430 LSISAS3108(EFI/UEFI模式)

    華為服務(wù)器RAID陣列卡配置教程 SR430 LSISAS3108(EFI/UEFI模式)

    最近采購了華為服務(wù)器的服務(wù)器第一次做陣列,沒想到使用了以后發(fā)現(xiàn)與dell的陣列卡配置差不多,這里就為大家分享一下SR430 LSISAS3108EFI/UEFI模式下陣列卡的配置方法
    2025-02-02
  • 手把手教你搭建騰訊云服務(wù)器入門(圖文教程)

    手把手教你搭建騰訊云服務(wù)器入門(圖文教程)

    這篇文章主要介紹了手把手教你搭建騰訊云服務(wù)器入門,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • windows和Linux使用命令行計算文件的MD5值

    windows和Linux使用命令行計算文件的MD5值

    在Windows和Linux系統(tǒng)中,您可以使用命令行(終端或命令提示符)來計算文件的MD5值,文章介紹了在Windows和Linux/macOS系統(tǒng)上計算文件MD5值的方法
    2025-05-05

最新評論