我正在尝试使用 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++ 不是一种安全的语言。经历未定义的行为并不意味着程序崩溃,它意味着您不能依赖 C++ 的规则来预测程序的行为。任何事都有可能发生。