C ++ lambda对象的地址作为函数的参数

时间:2012-12-09 15:03:01

标签: c++ c++11 lambda

根据我的经验,似乎要么:

  • 在函数调用中创建的lambda表达式在调用
  • 之后被销毁
  • 调用一个期望std::function的函数从lambda中创建一个临时对象(std :: function),并在调用后销毁该对象

使用以下代码段可以观察到此行为:

const function<void()>* pointer;

void a(const function<void()> & f)
{
    pointer = &f;
}

void b()
{
    (*pointer)();
}

int main()
{
    int value = 1;
    std::cout << &value << std::endl;

    // 1: this works    
    function<void()> f = [&] () { std::cout << &value << std::endl; };
    a(f);

    // 2: this doesn't
    a([&] () { std::cout << &value << std::endl; });

    /* modify the stack*/
    char data[1024];
    for (int i = 0; i < 1024; i++)
        data[i] = i % 4; 

    b();

    return 0;
}

第二种情况究竟发生了什么? 是否有正确的方法可以在不创建显式a()对象的情况下调用std::function

修改: 这两个版本(1和2)编译得恰到好处,但会产生不同的输出:

版本1:

0x7fffa70148c8
0x7fffa70148c8

第2版:

0x7fffa70148c8
0

3 个答案:

答案 0 :(得分:2)

如果你创建一个临时的,它将在该行的末尾消失。这意味着存储指向它的指针是一个坏主意,正如您所说的那样。

如果要存储指向std::function(或其他任何其他内容)的指针,则需要确保在停止使用指针之前它的生命周期没有结束。这意味着您确实需要类型为std::function的命名对象。

关于第二种情况发生的情况:您创建一个临时的lambda传递给函数。由于函数需要std::function,因此将从lambda创建临时std::function。这两个都将在该行的末尾被销毁。因此,您现在有一个指向已经销毁的临时对象的指针,这意味着尝试使用指向的对象将使您牢固地进入未定义的行为区域。

答案 1 :(得分:1)

无国籍的lambdas 是可以的。无状态lambda具有对函数指针类型的隐式转换。

此外,总是隐式转换为std :: function&lt;&gt;无论实际的可调用类型如何。

保留指向临时对象的指针存在问题,但。我在第一次阅读代码时没有注意到。

当然,这与std :: function无关。

答案 2 :(得分:0)

临时对象在创建它们的语句的末尾被销毁。你刚刚用lambda演示了这个。

第一次传递的std函数不是临时函数,因此它与变量一样长。它实际上存储了临时的副本。

要让你的lamdas持续超过一行,你需要将它存储在某个地方,并确定其寿命。

有很多方法可以做到这一点。 Std函数是一种基于类型擦除的存储方式 - 即存储std函数而不是指向std函数的指针。将pointer的类型更改为非指针(和非const),在分配时删除&,并直接调用它。

通常避免将const引用函数参数的地址作为临时绑定并将其存储为临时绑定,除非您在另一个重载中捕获rvalue引用的可能性。