我使用高阶函数,当我创建两个实例并将它们分配给变量时,我开始得到不同的结果。
我将问题简化为以下示例:
#include <iostream>
using ColorGetter = int(*)(void);
auto paint(const ColorGetter &f)
{
return [&]() { return f(); };
}
int colorA() { return 10; }
int colorB() { return 20; }
int main()
{
auto painter1 = paint(colorA);
auto painter2 = paint(colorB);
std::cout << "painter 1 : " << painter1() << "\n";
std::cout << "painter 2 : " << painter2() << "\n";
auto p1 = [] () { return colorA(); };
auto p2 = [] () { return colorB(); };
std::cout << "p 1 : " << p1() << "\n";
std::cout << "p 2 : " << p2() << "\n";
}我的期望是从这两个序列中得到10,然后是20。相反,根据编译器的不同,我得到:
➜ tmp clang++-13 -o out.gcc wrong.cpp&& ./out.gcc
painter 1 : 10
painter 2 : 20
p 1 : 10
p 2 : 20
➜ tmp g++-11 -o out.gcc wrong.cpp && ./out.gcc
painter 1 : 20
painter 2 : 20
p 1 : 10
p 2 : 20上面的代码有什么根本问题吗?我没有编译器警告或clang-整洁的问题,至少在我当前的设置。
发布于 2022-05-25 17:18:22
让我们看看下面的代码:
auto paint(const ColorGetter &f)
{
return [&]() { return f(); };
}f参数仅存在于函数paint的生存期内。您的lambda函数通过引用(即[&]位)捕获它,因此您的lambda捕获将引用函数结束后不再存在的变量(引用f)。因此,要返回的对象保持对函数的悬空引用。您在这里看到了未定义的行为,这就是为什么结果因编译器而异的原因。
若要解决此问题,请将代码更改为
auto paint(const ColorGetter &f)
{
return [=]() { return f(); };
}这将导致lambda捕获创建存储在f (指向所述函数的指针)中的值的副本,这将超过paint函数。
发布于 2022-05-25 17:19:03
你没有记录一辈子的事。
auto paint(const ColorGetter &f)
{
return [&]() { return f(); };
}这捕获了对f的引用。当lambda超过其创建的作用域时,您几乎不应该使用[&]。
f是:
auto painter1 = paint(colorA);在这一行上创建的临时指针。它在语句末尾被丢弃。
所以您的代码,当它执行f()时,会显示出未定义的行为--您正在跟踪一个悬空引用。
简单的解决办法包括:
auto paint(const ColorGetter &f)
{
return [=]() { return f(); };
}我还会去掉指针引用:
auto paint(const ColorGetter f)
{
return [=]() { return f(); };
}当我在做的时候。盲目地争论const&是一种坏习惯。就像盲目对待事物一样。知道你经过的是什么。
https://stackoverflow.com/questions/72381803
复制相似问题