1

I want just to print a vector with for_each.

using namespace std;
struct Print {
   int z = 0;
   void operator()(int i) {
      if (z) cout << ' ';
      cout << i;
      z = 1;
   }
   ~Print() {
      if (z) cout << endl;
   }
};
main() {
   vector<int> v = {1, 2, 3, 4, 5};
   for_each(begin(v), end(v), Print());
}

It works wrong, it calls destructor two times and prints two newlines instead of one. Why? Can anybody explain the logic of this odd behavior? BTW it works fine with the ugly global variable.

int z;
struct Print {
   void operator()(int i) {
   . . .
};

I am using GCC.

vollitwr
  • 429
  • 2
  • 8
  • 2
    `for_each` takes its 3rd argument *by value*... – Oliver Charlesworth Oct 18 '15 at 18:13
  • How are you determining that? – Oliver Charlesworth Oct 18 '15 at 19:18
  • I've added a constructor - it was called once but the destructor twice. – vollitwr Oct 18 '15 at 19:28
  • 1
    Have you implemented the default constructor and the copy constructor? – Gene Oct 18 '15 at 20:37
  • Wow! It was the main problem. Thank you very much! You've eventually solved this issue. A lot of thanks to you again and to Bo Persson. So the logic of the code becomes clear. – vollitwr Oct 18 '15 at 20:46
  • You could get rid of `z` and have the `operator()` just do `cout << i;` and write `cout << endl;` after the `for_each` call... that would be much easier to read and more flexible too. If you want to link the two together then make a function that calls `for_each` and then `cout << endl`. – M.M Oct 18 '15 at 22:01

3 Answers3

3

It's not "wrong". You forgot that the predicate is copied, at least once. In fact, it is legal for the predicate to be copied many times. Your class should take that into account; and not by making its members static (which breaks subsequent invocations). std::for_each is not really the right tool for this job.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

Check the signature of for_each

template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );

It returns a copy of the function object.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Is there way to do this print without global variables? – vollitwr Oct 18 '15 at 18:26
  • `for_each(begin(v), end(v), [](int i){ std::cout << i << ' '; });` assuming C++11. – WhiteViking Oct 18 '15 at 18:27
  • It leaves a trailing space! What to do if somebody wants comma separated list? Is there a way to trace multiple destructor calls? – vollitwr Oct 18 '15 at 18:30
  • Correct - but that was a bit implicit in your question. What are your precise requirements? Do you insist on using `std::for_each()`? Is a trivial loop with *local* variables fine? Is using Boost acceptable? What version of C++? Etc. – WhiteViking Oct 18 '15 at 18:37
  • 1
    If this question is not about the issue with the destructor anymore, then it is a duplicate: http://stackoverflow.com/questions/3496982/printing-lists-with-commas-c and http://stackoverflow.com/questions/6692880/how-to-deal-with-last-comma-when-making-comma-separated-string and ... – WhiteViking Oct 18 '15 at 18:41
0

I found much better solution. Both constructors should be explicitly included into Print class.

Print() {}
Print(const Print&) {}

Thanks to Bo Persson and Gene who explained the logic.

vollitwr
  • 429
  • 2
  • 8