C++:如果 lambda 表达式通过引用捕获右值会怎样[重复]

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

我正在尝试使用 lambda 表达式将一些函数包装为 void() 函数。代码如下:

class VoidFunctionWrapper
{
public:
    VoidFunctionWrapper()
    {
        function_ = []() {};
    }

    template <typename Function, typename... Args>
    VoidFunctionWrapper(Function &&function, Args &&...args)
    {
        wrap_function(std::forward<Function>(function), std::forward<Args>(args)...);
    }

    void wrap_function(std::function<void()> function)
    {
        function_ = std::move(function);
    }

    template <typename Function, typename... Args>
    std::enable_if_t<!std::is_same_v<std::decay_t<Function>, std::function<void()>>, void>
    wrap_function(Function &&function, Args &&...args)
    {
        std::function<void()> function_lambda = [&]() mutable
        { function(std::forward<Args>(args)...); };

        wrap_function(function_lambda);
    }

    std::function<void()> get_wrapped_function()
    {
        return function_;
    }
private:
    std::function<void()> function_;
};

VoidFunctionWrapper
将函数包装到
std::function<void()>
实例。关键成员函数是:

    template <typename Function, typename... Args>
    std::enable_if_t<!std::is_same_v<std::decay_t<Function>, std::function<void()>>, void>
    wrap_function(Function &&function, Args &&...args)
    {
        std::function<void()> function_lambda = [&]() mutable
        { function(std::forward<Args>(args)...); };

        wrap_function(function_lambda);
    }

首先声明,我理解这个函数是不正确的,因为捕获列表应该使用

[=]
而不是
[&]
但是,当使用这个“错误”版本的代码与
[&]
时,我真的做这个测试很困惑:

int main()
{
    // A test function to set a bool variable to true with a bool pointer
    // It changes the value and print the address

    std::function<void(bool *)> check = [](bool *ptr)
    { 
        std::cout << ptr << std::endl;
        *ptr = true; 
    };

    // Configure some tasks to execute
    
    std::vector<VoidFunctionWrapper> tasks_to_execute;
    std::deque<bool> check_list(5, false);
    for (size_t i_check = 0; i_check < check_list.size(); i_check++)
    {
        VoidFunctionWrapper temp_func = VoidFunctionWrapper(check, &(check_list[i_check]));
        tasks_to_execute.push_back(std::move(temp_func));
    }
    
    for (size_t i_check = 0; i_check < check_list.size(); i_check++)
    {
        tasks_to_execute[i_check].get_wrapped_function()();
    }

    for (size_t i_check = 0; i_check < check_list.size(); i_check++)
    {
        std::cout << check_list[i_check] << " ";
    }
    std::cout << std::endl;
}

结果是:

0x7f9506008804
0x7f9506008804
0x7f9506008804
0x7f9506008804
0x7f9506008804
0 0 0 0 1 

我注意到使用捕获列表

&(check_list[i_check])
时传递
[&]
可能是不正确的。这个r值
&(check_list[i_check])
可能会超过调用最终包装函数时的生存期。我对我的代码的行为感到非常困惑。当尝试调用包装函数时,我期待一个“悬空指针”,但是,这不会发生。

简而言之,我想知道 lambda 表达式中捕获的 r 值

&(check_list[i_check])
如何工作,使所有
VoidFunctionWrapper
实例更改同一变量的值。

c++ lambda
1个回答
0
投票

您确实有悬空引用,并且它们的使用具有未定义的行为。让您感到惊讶的是未定义行为的特定症状。

C++ 不是一种安全的语言。经历未定义的行为并不意味着程序崩溃,它意味着您不能依赖 C++ 的规则来预测程序的行为。任何事都有可能发生。

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