Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Address of lambda objects as parameters to functions

Tags:

c++

c++11

lambda

From my experience it seems that either:

  • A lambda expression created inside a function call is destroyed just after the invocation
  • Calling a function that expects a std::function creates a temporary object (std::function) out of the lambda, and that object is destroyed after invocation

This behavior can be observed with the following snippet of code:

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;
}

What exactly s actually happening in the second case? Is there a correct way to call a() without creating an explicit std::function object?

Edit:: This both versions (1 and 2) compile just right but result in different outputs:

Version 1:

0x7fffa70148c8
0x7fffa70148c8

Version 2:

0x7fffa70148c8
0
like image 293
João Rafael Avatar asked Dec 09 '12 15:12

João Rafael


2 Answers

If you create a temporary, it will be gone at the end of the line. This means storing a pointer to it is a bad idea, as you correctly stated.

If you want to store a pointer to a std::function (or anything else really), you need to make sure it's lifetime doesn't end before you stop using the pointer. This means that you really do need a named object of type std::function.

As to what is happening in the second case: You create a temporary lambda to be passed to the function. Since the function expects a std::function, a temporary std::function will be created from the lambda. Both of those will be destroyed at the end of the line. Therefore you now have a pointer to an already destroyed temporary, which means that trying to use the pointed to object will bring you firmly into undefined behaviour territory.

like image 128
Grizzly Avatar answered Nov 15 '22 01:11

Grizzly


It's okay for stateless lambdas. Stateless lambdas have an implicit conversion to function pointer type.

Also, there is always an implicit conversion to std::function<> regardless of the actual callable type.

There are problems with keeping a pointer to temporaries, though. I hadn't noticed that on first reading of the code.

That has nothing to do with std::function, of course.

like image 42
sehe Avatar answered Nov 15 '22 00:11

sehe