Edit: Marked as duplicate (sort of, there is no undefined behavior, only unspecified), I was fooled by the artificial complexity of lambda capture by move, which is not relevant.
My coworkers and I have discovered a strange discrepancy between GCC 6, 7 and Clang when we try to capture a variable by move after using it by const reference in the same statement. A minimal example:
#include <iostream>
#include <string>
struct A
{
template <class F> void call (F f)
{
f();
}
};
A test(const std::string& s)
{
std::cout << "in method: " << s << std::endl;
return {};
}
int main()
{
std::string s = "hello";
test(s).call([s = std::move(s)] { std::cout << "in lambda: " << s << std::endl;});
return 0;
}
Wandbox link: https://wandbox.org/permlink/TMoB6EQ7RxTJrxjm
Output in GCC 6.3:
in method:
in lambda: hello
Output in GCC 7.2 and Clang:
in method: hello
in lambda: hello
Note that using two statements, i.e. auto t = test(s); t.call(...);
gives the same (second) result with GCC 6.3. We were naively expecting the second output everywhere: is it a GCC 6 bug, an undefined behavior or a standard change?
For info our "real-life" case is asynchronous call: test
is the call, struct A
is the result which expects a callback.