1

Why does this result in a segmentation fault?

#include <iostream>
#include <functional>
using namespace std;

int main() {

     function<int(int,int)> hcf = [=](int m, int n)mutable->int{
    // cout << "m: " << m << " n: " << n << endl;
    if(m<n) return hcf(n,m);
    int remainder(m%n);
    if(0 == remainder) return n;
    return hcf(n,remainder);
};

    cout << hcf(10,15) << endl;

    return 0;
}

I have added the mutable keyword. Shouldn't pass-by-value work? Why does this require pass-by-reference? Is it because I am calling hcf recursively?

Quaxton Hale
  • 2,460
  • 5
  • 40
  • 71
  • 2
    capturing by value `hcf` at the point it's not initialized doesn't sound like a good idea – Piotr Skotnicki Oct 13 '14 at 17:21
  • You don't supply the error message. Funnily enough it works for me without error. Although I am wondering how it captures `cout` by copy - shouldn't that be deleted? – Galik Oct 13 '14 at 17:31
  • 2
    this question should not be downvoted, it can become a common problem soon – Piotr Skotnicki Oct 13 '14 at 17:31
  • 1
    @Galik: `std::cout` is a global instance, does not need to be captured. and it compiles, but it should throw exception `std::bad_function_call` – Piotr Skotnicki Oct 13 '14 at 17:33
  • I meant it results in a segmentation fault. I was running this on an online compiler and it just said runtime error. – Quaxton Hale Oct 13 '14 at 17:40
  • @Galik I have updated the code. Sorry about the confusion. – Quaxton Hale Oct 13 '14 at 17:42
  • 1
    I think I get it now. That it uses `cout` without capturing it is a big clue as to why it works as a global `lambda` but not as a local `lambda`. When it is global it can call itself without having to capture itself. When its local it needs to capture itself to call itself and so capture by copy is problematic! – Galik Oct 13 '14 at 18:02
  • Could someone give me a link to the specs for this? I couldn't find documentation for this behavior. – Quaxton Hale Oct 13 '14 at 18:27
  • Possible duplicate of [Recursive lambda functions in C++11](http://stackoverflow.com/questions/2067988/recursive-lambda-functions-in-c11) –  Nov 28 '16 at 21:06

1 Answers1

5

The closure object is initialized before hcf as it is hcf's initializer. Even if your code wouldn't invoke UB you would still copy hcfs still empty state into the member variable of the closure object. Subsequently calling it would then result in calling an empty function.

When you capture by reference this isn't a problem anymore as with the references first use (that is, the first call to the closure object), hcf has already been properly initialized.

Columbo
  • 60,038
  • 8
  • 155
  • 203