Dangling reference in inner lambda [duplicate]
Asked Answered
L

3

14

I have an inner lambda that uses one of the referenced variables of the outer lambda like this:

int x=0;
auto outer=[&](){
   return [&](){
        x=5;
    };
};

auto inner= outer();
inner();
std::cout << x;

I tried it. It worked well. However, I want to make sure that there is no dangling reference here. Is there?

Lawler answered 24/4, 2017 at 9:10 Comment(1)
The way I see it - it's the reference to the same x, and since you didn't leave the scope where it was defined - it isn't a dangling reference. But, I'll let more knowledgeable people on SO answer it.Footstalk
M
16

There is no dangling reference here. The reference of the inner lambda is not a reference to a reference (there is no such thing); it refers to x - which of course didn't go out of scope.

Mudfish answered 24/4, 2017 at 9:31 Comment(5)
So, it is true there is no longer such a thing as "references to references", and never really was. But there was a defect in C++11 that tied the lifetime of reference captured variables in lambdas to the lifetime of the reference variable they captured, not to the lifetime of the thing they where referring to. There where even optimization related reasons why this might be a good idea (as it permitted [&] lambdas to capture a stack-frame pointer and optionally a this pointer and nothing else).Dalmatian
@Yakk That's interesting. Thanks for pointing it out. I'm glad that my assumption is the intention of the standard.Mudfish
I now believe I am wrong. Read the accepted answer hereDalmatian
@Yakk the answer seems similar to what you said, except according to it seems that the wording that breaks this code was added after C++14, and the that it should (hopefully?) be fixed before C++17 is released.Mudfish
Yes, it was convoluted but safe in C++11 and C++14. Then wording was added post C++14 and fixed prior to C++17 that led to the problem. The issue was that the wording to fix it wasn't at the same spot where the the rewording that caused the problem! So I (and the original answer to the link) was confused and thought it was a defect in C++14 being fixed; actually it was a C++17 defect being fixed prior to C++17 being finalized.Dalmatian
W
7

As shown, you're calling the lambda within the block scope where x is declared, and there's no dangling reference.

It's worth noting that the inner anonymous lambda captures the reference to x directly from the outermost block scope rather than from the outer lambda, since it's looking for the declaration.

If you pass (a copy of) your lambda object outside that block scope, then you can cause a dangling reference.

Wicked answered 24/4, 2017 at 9:39 Comment(0)
B
4

If you rewrite the code without using lambdas then I think it is clear there is no dangling reference, simply a reference to a variable x that is still in scope:

class Inner {
    int& x;
  public:
    Inner(int &x) : x(x) {}
    void operator()(){
        x = 5;
    }
};

class Outer {
    int& x;
  public:
    Outer(int &x) : x(x) {}
    Inner operator()(){
        return {x};
    }
};

int main() {
    int x=0;
    auto outer = Outer{x};
    auto inner = outer();
    inner();
    std::cout << x;
}
Bowfin answered 24/4, 2017 at 9:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.