簡體   English   中英

Lambda:可以懸掛的副引用捕獲

[英]Lambda: A by-reference capture that could dangle

有效的現代C ++中的Scott Meyers在lambda章節中說:

請考慮以下代碼:

void addDivisorFilter()
{
    auto calc1 = computeSomeValue1();
    auto calc2 = computeSomeValue2();

    auto divisor = computeDivisor(calc1, calc2);

    filters.emplace_back(
          [&](int value) { return value % divisor == 0; }
    );
}

這段代碼是一個等待發生的問題。 lambda引用局部變量divisor ,但當addDivisorFilter返回時,該變量不再存在。 這是在filters.emplace_back返回后立即執行的,因此添加到filters的函數在到達時基本上是死的。 使用該過濾器幾乎從創建時開始產生未定義的行為。

問題是:為什么它是一個未定義的行為? 根據我的理解, filters.emplace_back僅在lambda表達式完成后返回,並且在執行期間, divisor有效。

更新

我錯過的重要數據包括:

using FilterContainer = std::vector<std::function<bool(int)>>;
FilterContainer filters;

那是因為向量filters的范圍超過了其中一個函數。 在函數出口處,向量filters仍然存在,並且捕獲的對divisor引用現在是懸空的。

根據我的理解,filters.emplace_back僅在lambda表達式完成后返回,並且在執行期間,除數有效。

這不是真的。 向量存儲從閉包創建的lambda,並且不“執行”lambda,在函數退出后執行lambda。 從技術上講,lambda是從一個內部使用引用的閉包(一個依賴於編譯器的類)構造的

#include <vector>
#include <functional>

struct _AnonymousClosure
{
    int& _divisor; // this is what the lambda captures
    bool operator()(int value) { return value % _divisor == 0; }
};

int main()
{
    std::vector<std::function<bool(int)>> filters;
    // local scope
    {
        int divisor = 42;
        filters.emplace_back(_AnonymousClosure{divisor});
    }
    // UB here when using filters, as the reference to divisor dangle
}

在addDivisorFilter處於活動狀態時,您沒有評估lambda函數。 您只是將“函數”添加到集合中,而不知道何時可以對其進行評估(可能在addDivisorFilter返回后很長時間)。

除了@ vsoftco的答案之外,以下修改過的示例代碼可以讓您體驗到這個問題:

#include <iostream>
#include <functional>
#include <vector>

void addDivisorFilter(std::vector<std::function<int(int)>>& filters)
{
    int divisor = 5;

    filters.emplace_back(
          [&](int value) { return value % divisor == 0; }
    );
}

int main()
{
    std::vector<std::function<int(int)>> filters;
    addDivisorFilter(filters);
    std::cout << std::boolalpha << filters[0](10) << std::endl;
    return 0;
}

實例

此示例在運行時導致Floating point exception ,因為當在main計算lambda時,對divisor的引用無效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM