简体   繁体   中英

C++ Address of lambda objects as parameters to functions

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

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.

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.

Temporary objects are destroyed at the end of the statement they are created in. You have just demonstrated this with a lambda.

The std function you pass the first time is not a temporary, so it lasts as long as the variable. It actually stores a copy of the temporary.

To have your lamdas last more than a line, you need to store it somewhere and have its lifetime determined.

There are many ways to do this. Std function is a type erasure based way to do the storage -- ie, store a std function instead of a pointer to a std function. Change the type of pointer to being a non pointer (and non const), get rid of the & when you assign to it, and call it directly.

In general avoid taking and storing the address of const reference function parameters as temporary bind to them, unless you catch the rvalue reference possibility in another overload.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM