Search code examples
c++rvalue-reference

Why do references to moved values not dangle after the lvalue that the object was moved into goes out of scope?


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)>&)?


Solution

  • 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)