什么时候通过引用在另一个lambda中捕获一个lambda是安全的?

问题描述 投票:1回答:1

假设你有以下程序。

static std::function<int(int)> pack_a_lambda( std::function<int(int)> to_be_packed ) {
    return [=]( int value ) {
        return to_be_packed( value * 4 );
    };
}

int main() {
    auto f = pack_a_lambda( []( int value ) {
        return value * 2;
    } );

    int result = f( 2 );

    std::cout << result << std::endl; // should print 16
    return 0;
}

我还没试过上面的代码,因为我在谷歌测试中测试过 然后像上面一样稍加编辑。那么,函数 pack_a_lambda 将一个lambda的值作为输入。这里,我相信临时lambda是被复制的。然后,当我们创建新的lambda时,我们再次捕获复制的lambda。to_be_packed 按价值计算。它可以工作,而且在我看来它应该是安全的。

现在假设我们通过引用来捕获这个lambda。

static std::function<int(int)> pack_a_lambda( std::function<int(int)> to_be_packed ) {
    return [&]( int value ) {
        return to_be_packed( value * 4 );
    };
}

在我的特定用例中,产生的lambda的执行速度快了四倍。不过在上面的简化示例中,我无法再现这种差异。事实上,在这里,通过引用捕获lambda似乎使它的速度稍稍慢了一些。所以很明显是有一些性能上的差异。

但它安全吗?争论 to_be_packed 是复制的,但还是临时的吧?这样应该就不安全了。但我不确定。我的UB sanitizer和我的AddressSanitizer没有抱怨,但我承认这并不能证明什么。如果我通过 to_be_packed 通过引用...

static std::function<int(int)> pack_a_lambda( const std::function<int(int)> &to_be_packed ) {
    return [&]( int value ) {
        return to_be_packed( value * 4 );
    };
}

...AddressSanitizer抱怨,这并不奇怪,因为我传入函数的lambda也是一个临时的。所以就剩下例子二了:它到底安不安全,有什么可能的原因让它在某些情况下执行得更快?

c++ lambda pass-by-reference
1个回答
1
投票
static std::function<int(int)> pack_a_lambda( std::function<int(int)> to_be_packed ) {
    return [&]( int value ) {
        return to_be_packed( value * 4 );
    };
}

这是一个未定义的行为,因为你 "返回 "对本地变量的引用。

static std::function<int(int)> pack_a_lambda(const std::function<int(int)>& to_be_packed ) {
    return [&]( int value ) {
        return to_be_packed( value * 4 );
    };
}

可能是正确的,你必须确保传递参数的寿命比返回的长。std::function.

auto func = std::function([]( int value ) {
        return value * 2;
    });
auto f = pack_a_lambda(func); // OK
// auto f2 = pack_a_lambda([](int){ return 42;}); // KO: temporary std::function created

作为临时性的可以绑定到const引用,在这种情况下,删除r值版本更安全。

static std::function<int(int)> pack_a_lambda(std::function<int(int)>&&) = delete;

1
投票

什么时候通过引用在另一个lambda中捕获一个lambda是安全的?

和任何捕获的对象一样:当捕获对象的寿命比捕获的lambda长时才是安全的。

在你的例子中,你捕获了一个函数参数。它的寿命在函数返回时结束。但你将捕获的lambda返回到函数的外部。在那里,捕获的引用将是无效的。

© www.soinside.com 2019 - 2024. All rights reserved.