最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2025年09月19日 09:03:49   作者: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)慎使用隱式捕獲,尤其是 [&],因?yàn)樗赡茏屇銦o意中修改外部變量或引入懸空引用。

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::thread、std::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(因?yàn)闊o法拷貝),但可以用 [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 的生命周期可能比對象更長(例如,被放入一個全局隊(duì)列),這會導(dǎo)致懸空 this 指針。C++17 的 [\*this] 可以按值捕獲整個對象的副本,避免這個問題。

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

相關(guān)文章

  • Linux下動靜態(tài)庫的打包與使用指南(C/C++)

    Linux下動靜態(tài)庫的打包與使用指南(C/C++)

    c++是面向?qū)ο蟮木幊陶Z言,比較方便實(shí)現(xiàn)某些第三方庫,比如翻譯其他面向?qū)ο笳Z言的代碼,比c語言要方便的多,下面這篇文章主要給大家介紹了關(guān)于Linux下C/C++動靜態(tài)庫的打包與使用的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • C++運(yùn)算符重載圖文詳解

    C++運(yùn)算符重載圖文詳解

    運(yùn)算符重載的方法是定義一個重載運(yùn)算符的函數(shù),在需要執(zhí)行被重載的運(yùn)算符時,系統(tǒng)就自動調(diào)用該函數(shù),以實(shí)現(xiàn)相應(yīng)的運(yùn)算。也就是說,運(yùn)算符重載是通過定義函數(shù)實(shí)現(xiàn)的
    2021-09-09
  • C++數(shù)據(jù)結(jié)構(gòu)之哈希算法詳解

    C++數(shù)據(jù)結(jié)構(gòu)之哈希算法詳解

    這篇文章主要為大家詳細(xì)介紹了C++數(shù)據(jù)結(jié)構(gòu)中哈希算法的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,希望對大家有所幫助
    2022-12-12
  • C語言結(jié)構(gòu)體使用之鏈表

    C語言結(jié)構(gòu)體使用之鏈表

    這篇文章主要介紹了C語言結(jié)構(gòu)體使用之鏈表,下面文章主要圍繞結(jié)構(gòu)體的概念和用法、結(jié)構(gòu)體數(shù)組和結(jié)構(gòu)體指針、包含結(jié)構(gòu)體的結(jié)構(gòu)體、結(jié)構(gòu)體搭建鏈表方法、結(jié)構(gòu)體及鏈表在產(chǎn)品應(yīng)用場景等多個主題展開鏈表的相關(guān)資料,需要的小伙伴可以參考一下
    2022-03-03
  • C++ 自增、自減運(yùn)算符的重載和性能分析小結(jié)

    C++ 自增、自減運(yùn)算符的重載和性能分析小結(jié)

    這篇文章主要介紹了C++ 自增、自減運(yùn)算符的重載和性能分析小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 詳解c語言中的 strcpy和strncpy字符串函數(shù)使用

    詳解c語言中的 strcpy和strncpy字符串函數(shù)使用

    strcpy 和strcnpy函數(shù)是字符串復(fù)制函數(shù)。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數(shù)使用,感興趣的朋友跟隨小編要求看看吧
    2018-10-10
  • VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法

    VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法

    本文主要介紹了VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • C語言詳解格式控制符scanf與printf的輸入輸出

    C語言詳解格式控制符scanf與printf的輸入輸出

    這篇文章主要介紹了C語言格式控制符中輸入scanf()和輸出printf()的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2022-04-04
  • windows?使用ffmpeg?.a靜態(tài)庫讀取Wav音頻并保存PCM的方法

    windows?使用ffmpeg?.a靜態(tài)庫讀取Wav音頻并保存PCM的方法

    這篇文章主要介紹了windows?使用ffmpeg?.a靜態(tài)庫讀取Wav音頻并保存PCM,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-02-02
  • VisualStudio2022提交git代碼的方法實(shí)現(xiàn)

    VisualStudio2022提交git代碼的方法實(shí)現(xiàn)

    本文主要介紹了VisualStudio2022提交git代碼的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07

最新評論

新巴尔虎右旗| 漾濞| 论坛| 庆云县| 布尔津县| 深泽县| 鄂托克旗| 广德县| 江都市| 射洪县| 峨眉山市| 文水县| 松原市| 遂昌县| 铜陵市| 合川市| 建始县| 鹤山市| 连州市| 梅州市| 南澳县| 嘉定区| 昌吉市| 错那县| 庐江县| 原平市| 新蔡县| 淮阳县| 定西市| 石渠县| 木兰县| 咸宁市| 梧州市| 星座| 通城县| 科尔| 连江县| 株洲市| 扶余县| 张家港市| 陇西县|