简体   繁体   中英

Static variables in C++ lambdas

The following code works fine:

#include <iostream>
#include <functional>

std::function<int (void)> get_incrementer() {
    return []() {
        static int count = 0;
        return count++;
    };
}

int main() {
    using std::cout;

    auto incrementer = get_incrementer();

    cout << incrementer() << std::endl;
    cout << incrementer() << std::endl;

    return 0;
}

But if you capture a local variable by reference instead, it suddenly results in undefined behaviour, presumely because at call-time that location on the stack is being used by something else.

std::function<int (void)> get_incrementer() {
    int count = 0;

    return [&count]() {
        return count++;
    };
}

Why does the compiler allow it though? I expected the compiler to either not allow this (it seems trivial to check for this case) or change the storage duration of the local variable.

C++ allows it because C++ is not a safe language. And while this case may be "trivial" to check for (and personally, I don't agree that it's trivial, but I'm not a compiler writer), there are plenty of other cases that are not trivial to check for.

C++ is not in the business of fixing your broken code for you. It does exactly and only what you tell it to, even if it's massively unwise.

Furthermore, it's not entirely clear exactly what it is that you were intending this code to do. For example, these are two completely different things:

std::function<int (void)> get_incrementer() {
    return []() {
        static int count = 0;
        return count++;
    };
}

std::function<int (void)> get_incrementer() {
    int count = 0;
    return [count]() mutable {
        return count++;
    };
}

In the first case, every instance of the returned function will share the same increment count. In the second case, each time you call get_incrementer , you will get a separate object with it's own increment count.

Which one did the user want? It's not clear. So you can't just willy-nilly "correct" it.

You explicitly tell the compiler that you want to take the variable by reference, so it assumes that you have your reasons and does what you tell it to do.

You are the master, the compiler is merely there to serve your needs and obey your wishes. It might warn you in certain cases when it thinks you are doing something particularly strange, but if you insist, it respects you authority and compiles that strange looking code.

Using references to local variables after the local variable went out of scope is always undefined behavior and won't do any good, using a lambda to do it is not all that special.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM