0

Is the following code legal:

std::function<void()> CreateFunction(int i, std::function<void()> previous_f) {
   return [i,previous_f] { 
     std::cout << i << std::endl;
     previous_f();
   };
}


int main()
{
  std::function<void()> f = []{};
  for(int i=0;i<3;++i) {
    f = CreateFunction(i, f);
  }
  f();
}

It compiles and runs as expected - http://cpp.sh/2smb3, but I am concerned that assigning to an f after f have been moved may invoke undefined behavior.

Ilya Kobelevskiy
  • 5,245
  • 4
  • 24
  • 41
  • 1
    More general question: https://stackoverflow.com/questions/7027523/what-can-i-do-with-a-moved-from-object/7028318 – NathanOliver Dec 18 '18 at 20:03
  • 3
    Actually, you're not using a moved from object in your code. The link is still a good read but it doesn't apply here. – NathanOliver Dec 18 '18 at 20:08

2 Answers2

1

Since you capture by value in the lambda ([i, previous_f] makes a copy of previous_f, completely detatched from the parameter you passed), it will be valid. In the end, f will (indirectly, in the context of the lambdas) hold copies of all the functions.

Note that you are not using std::move. However, even in that case, it would still be fine as you make copies which do not care that the original previous_f has been destructed.

Artyer
  • 31,034
  • 3
  • 47
  • 75
1

Whether or not this is safe depends upon whether the function-object is passed by value or by refernce. As your code illustrates, the function in "CreateFunction" is passed by value, and furthermore, copied by value within the returned lambda.

Because the function has been copied by value, the original value of 'f' is in no way required to resolve a call to the newly create function.

As a note, it may be better to use receive a const-reference within 'CreateFunction', as that would minimize the number of times the function object is copied by value.