Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference captured in static variable definition

Tags:

c++

c++11

#include <iostream>

void foo(int k) {
    static auto bar = [&]{
        std::cout << k << std::endl;
    };
    bar();
}

int main () {
    foo(1); foo(2); foo(3); // output is correct: 1, 2, 3
}

Check the function foo, an how the static lambda is capturing k by reference. This seems to work, and the same is happening with more complicated datatypes rather than int.

Is this expected? Is there any guarantee that the address of k will be the same for every invocation of foo, or is this UB?

Thanks in advance, and sorry if this was previously answered (I did try to find a similar question without success)

like image 436
José Manuel Avatar asked Apr 17 '13 22:04

José Manuel


People also ask

Are static variables passed by reference?

A static variable means that there is only one instance of it; compared to a member variable, for which there will be one variable for each instance of that class. It's nothing to do with passing by reference.

What does static keyword do in c#?

The static keyword in C is a storage-class specifier. It has different meanings, depending on the context. Inside a function it makes the variable to retain its value between multiple function calls. Outside of a function it restrains the visibility of the function or variable to the current file (compilation unit).


2 Answers

It is Undefined Behavior.

Per Paragraph 5.2.2/4 of the C++11 Standard about function call expressions and the initialization of their parameters:

[...] The lifetime of a parameter ends when the function in which it is defined returns. The initialization and destruction of each parameter occurs within the context of the calling function. [...]

Therefore, your lambda will be storing a reference that becomes dangling as soon as the function call returns.

In this case, implementations are free (and likely) to create function parameters at the same address for each function call, which is probably the reason why you are observing the expected output.

However, this behavior is not mandated by the Standard - therefore, you should not rely on it (if this was the case, your code would be legal because of 3.8/7).

like image 79
Andy Prowl Avatar answered Sep 18 '22 23:09

Andy Prowl


The reason it's probably "working" in your example is that the call stack is always lining up the same way. Try this instead and see if you still get the "expected" output.

#include <iostream>

void foo(int k) {
    static auto bar = [&]{
        std::cout << k << std::endl;
    };
    bar();
}

void baz(int k) {
    std::cout << "baz: ";
    foo(k);
}

int main () {
    foo(1); baz(2); foo(3);
}
like image 43
Timothy Shields Avatar answered Sep 21 '22 23:09

Timothy Shields