3

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.

balki
  • 26,394
  • 30
  • 105
  • 151

1 Answers1

3

In C++14, it's unspecified whether test(s) is evaluated first or if the lambda expression is evaluated first. There's no undefined behavior, however (assuming that test doesn't trigger UB with a moved-from string).

In C++17, test(s) is always evaluated before the lambda.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Indeed it is just related to sequence points. However, while playing with Wandbox it seems it is not related to standard version but to GCC version: GCC 6.3, with --std=c++14 or c++17: move is done first, whereas with GCC 7.1, with both standards, move is done after. EDIT: https://gcc.gnu.org/projects/cxx-status.html – Frédéric Samier Jan 09 '18 at 10:06
  • @FrédéricSamier It looks like the bulk of new stuff for C++17 landed in 7 only, which would make that unsurprising. – underscore_d Jan 09 '18 at 10:49