Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
226 views
in Technique[技术] by (71.8m points)

c++ - Lambda with dynamic storage duration

According to cppreference.com, C++11 lambda literal syntax is only legal to use in direct initialization. There doesn't seem to be a way to use the lambda syntax directly with the new operator.

I need to store a lambda function in the heap so that I can call it at some later point from a different thread. It's easy enough to make a copy of the lambda, but is there a simple way to allocate the lambda directly in the heap (dynamic storage duration) without first allocating it on the stack (automatic storage duration) and making a copy?

Here's a simple example:

#include <cstdio>
#include <cassert>

struct MyObj {
    int value;
    int copies;
    int moves;

    MyObj(int v): value(v), copies(0), moves(0) {
        printf("Created object with value %d.
", value);
    }

    MyObj(const MyObj &other): value(other.value),
    copies(other.copies+1), moves(other.moves) { }

    MyObj(const MyObj &&other): value(other.value),
    copies(other.copies), moves(other.moves+1) { }
};

int main (int argc, char **argv) {
    MyObj o { 5 };
    // Create lambda on stack (automatic storage duration)
    auto f = [o] {
        printf("Object value is %d
", o.value);
        printf("%d copies, %d moves...
", o.copies, o.moves);
    };
    // Copy lambda to heap (dynamic storage duration)
    decltype(f) *g = new decltype(f)(f);
    // Call the copy
    (*g)();
    return 0;
}

The above program makes 2 copies of o (one in the capture, and another when the lambda is copied into the heap). Ideally, there would only be one copy or move, which would happen when the heap-allocated lambda captures a copy of o.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

In C++11, a lambda expression will always result in some form of automatic object, whether a stack variable or an unnamed temporary. There's nothing you can do to change that.

In C++17, guaranteed elision gives us the ability to do this:

new auto(<lambda>)

This uses the memory allocated by new to store the result of that expression. There would be no temporary lambda object created here, nor would any copy/move constructor for the lambda be invoked. And most importantly, the language would not require that the lambda type have copy/move constructors that could be invoked.

You need guaranteed elision to ensure this however. Without that guarantee, then you're banking on the compiler to optimize it. The standard permits such cases to elide the copy. And yes, any compiler worth using probably would elide such copies.

With guaranteed elision, you could capture immobile types and this would still work without copying anything. Pre-C++17, your lambda would still need to have a copy or move constructor, even though the call to it is elided.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...