Michael Francis
Michael Francis

Reputation: 8757

Lambda variable capture

I'm confused about the nature of the variable capture part of a lambda expression.

void f1();
std::function<int()> f2;

int main() {
    f1();
    std::cout<<f2()<<endl;
}

void f1() {
    int x;
    f2 = [&]() {
        return x;
    };
}

Isn't x deconstructed before f2 is called?

Upvotes: 0

Views: 1225

Answers (2)

Robᵩ
Robᵩ

Reputation: 168876

Isn't x deconstructed before f2 is called?

Yes, it is. Which means that the return x evaluates a dangling reference, which invokes undefined behavior.

In this instance, you might prefer to capture by value.

f2 = [x]() { return x; }

Upvotes: 2

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275956

Yes. You have successfully invoked undefined behavior. One possible outcome is that you get the value of x. Another is that the computer formats your hard drive, the program crashes, or the computer transforms into a robotic baker-assassin that feeds you cupcakes, mistakenly thinking you have celiac disease.

A safe variant of this might be:

int main() {
    f1(7);
    std::cout<<f2()<<endl;
}

void f1(int x) {
    std::shared_ptr<int> spX( new int(x) );
    f2 = [=]() {
        return *spX;
    };
}

or

void f1(int x) {
    f2 = [=]() {
        return x;
    };
}

(for an int, there is little reason not to store it by value: for a more complex type, you might want to avoid copying it around needlessly).

Note that the comment above explains this in a funnier way.

Now, some compilers will mark the stack with special values when you decrement it to catch exactly this kind of undefined behavior (and by catch, I mean make it more obvious to the programmer). But for the most part, invoking undefined behavior in C++ is possible.

Upvotes: 4

Related Questions