3

I just find something that couldn't understand. I think it should be related to the functions stack and some undefined behavior.

Let's say I have a function factory template (silly one):

template <unsigned int N=10>
std::function<int&&(const int& n)> build_add_function() {
    return [](const int& n) -> int&& {std::move(n+N);};
}

As you can see, it lacks the return statement on a non-void function, hence the compiler throw me a warning... The strange thing is that it works "as expected"

int main() {
  auto foo = build_add_function();
  std::cout << foo(10);
}

main output: 20

Of course, to fix the code, I added the return statement and it gives me a segmentation fault

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

I have some misconception of what I'm doing for sure, but I just can not get it around. Would someone explain to me what is happening here? I'm using gcc version 8.0.1

EDIT: Just tested on gcc 4.8.1 and worked as expected with the return statement and no compilation errors.

Is it a compiler stuff?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Netwave
  • 40,134
  • 6
  • 50
  • 93

1 Answers1

6

Both the cases are undefined behavior.

The behavior of non-void function lacks return statement is undefined (except for main()), that means anything is possible. Even you might get the "correct" result you shouldn't rely on it.

When you added the return statement like return std::move(n+N);, you're trying to return a reference to temporary, which is always dangled, and dereference on it leads to UB too.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • the idea is that im marking the variable to be moved instead of copied, so the fix is just to use copy instead? – Netwave Aug 17 '18 at 09:31
  • so, would this work if it were for a custom class for example? or how to fix it then? – Netwave Aug 17 '18 at 09:34
  • @Netwave Sorry I was wrong. It has nothing to do with built-in types. Note that `std::move` doesn't perform move operation, it just converts the operand to rvalue. (BTW `std::move` is redundant in fact, `n+N` is already an rvalue.) So all what the lambda do is binding a temporary to the rvalue-reference and return it. The temporary is destroyed imediately, so the returned reference is always dangled. Change the return type to `int` would be fine. – songyuanyao Aug 17 '18 at 09:40
  • actually move may be redundant, but that is not the problem, the problem is that the compiler is complaining about using `move` directly on the operation without an intermediate storing variable. – Netwave Aug 17 '18 at 09:42
  • @Netwave You meant the compiler is complaining about `std::move(n+N)`? – songyuanyao Aug 17 '18 at 09:45
  • yes, exactly that, adding one more line make him understand – Netwave Aug 17 '18 at 09:45
  • @Netwave I think it complains because `n+N` is already an rvalue, using `std::move` is redundant. – songyuanyao Aug 17 '18 at 09:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178188/discussion-between-netwave-and-songyuanyao). – Netwave Aug 17 '18 at 09:48