0

While playing around with references to lambdas I encountered a scenario where I expected the program to crash due to dangling references. In the following program, I assumed that the lambda argument to fn_x_3 in main is "moved to" the fn_x_3 function because it's an rvalue, where it binds to the lvalue fn.

#include <iostream>
#include <functional>


std::function<int(int)> fn_x_3(std::function<int(int, int)>& fn) {
    // capture fn by reference!
    return [&fn](int x) {
        return fn(x, 3);
    };
}

std::function<int(int)> fn_x_3(std::function<int(int, int)>&& fn) {
    // passing fn (lvalue) by reference to fn_x_3 overload
    return fn_x_3(fn);
}

int main()
{
    // call to fn_x_3(function<int(int)>&& fn), lambda "moved into" the function
    auto fn = fn_x_3([](int x, int y){ return x + y; });
    int result = fn(2);
    std::cout << result << std::endl;
    return 0;
}

This program prints out 5. But when fn goes out of scope in fn_x_3(function<int(int,int)>&&), does this not invalidate the reference that is captured in fn_x_3(function<int(int,int)>&)?

Niklas Vest
  • 872
  • 6
  • 20
  • 3
    Note that "appears to work" is one of the many manifestations of undefined behaviour. – Adrian Mole Sep 14 '22 at 10:17
  • What makes you think that they do not dangle? If it is the "appearance of working and giving your expected output" then you might be surprised to know that: *"Undefined behavior means anything can happen including but not limited to the program giving your expected output. But never rely on the output of a program that has UB. The program may just crash"*. – Jason Sep 14 '22 at 10:30
  • Could have been also marked as duplicate of [this](https://stackoverflow.com/q/63977009/5825294). – Enlico Sep 14 '22 at 10:33
  • @Enlico Added it in the dupe list. – Jason Sep 14 '22 at 10:33
  • 1
    You have Undefined Behavior (UB) which is detected by sanitizer: https://godbolt.org/z/j196rb3vM UB doesn't mean crash. UB means anything can happen - [daemons can fly from your nose](https://en.wikipedia.org/wiki/Undefined_behavior). – Marek R Sep 14 '22 at 10:36
  • Thank you for the comments, I like the "never rely on the output of a program that has UB" part. IAN: don't just test the code, but also the compiler lmao – Niklas Vest Sep 14 '22 at 11:31

1 Answers1

1

It does, pretty much second function overload fn_x_3 is ok BUT if you use the return value in any way outside the scope of the function you are invoking UB by using object past its lifetime (the object is the underlying lambda structure of first fn_x_3 overload).

It is not enforced by the C++ compiler to block compilation of such programs. If you want to find these kinds of error you could use so called address sanitizers.

Programs prints 5 - it is most likely due to the fact that the memory that you are accessing is still "bound" to the executable thus it doesn't see any access violations (std::function implementation detail)

MichalK
  • 126
  • 3