I am C++ noob studying functors. I have this code as below(NB – This is not my homework, i am past that!).
It does print 0 1 2 3 4 5 6 7 8 9 on console
which I dont see how does it maintain the state of this object(value of n) if the functor is called by value and not by reference/pointer
EDIT:
I thought here(Example 1) since the functor is called by Value and the constructor initializes n to zero every time. So it should be zero always at beginning, then it should increment to 1 and return 1. How is it printing 0 1 2 3 4 5 6 7 8 9
Example 1]
class g
{
public:
g():n(0){}
int operator()() { return n++; }
int n;
};
;
int main()
{
int a[10];
g v1;
std::generate(a, a+10, g());//This passes a functor to generate
//EDIT - this will print 0 1 2 3 4 5 6 7 8 9**
std::copy(a, a+10, std::ostream_iterator<int>(std::cout, " "));
getchar();
return 0;
}
Because I have seen code like below using reference variables inside a functor to retain state, here and developed a simple code using that concept as below:
Example 2]
class CountingFunctor
{
public:
CountingFunctor() : _counter(0) {}
int getCounter(void) const {return(_counter);}
void operator () (Contained item) {if(item.getShouldBeCounted()) _counter++;}
private:
int _counter;
};
#endif
//this class uses references to maintain state in the functor
class CountingFunctor
{
public:
CountingFunctor(int &elem) : _counter(elem) {_counter=0;}
int getCounter(void) const {return(_counter);}
void operator () (Contained item) {if(item.getShouldBeCounted()) _counter++;}
private:
int &_counter;
};
int main()
{
vector<Contained> Container(10);
Container[3].setShouldBeCounted(false);
Container[9].setShouldBeCounted(false);
int elem;
CountingFunctor CountAllWhoShouldBe(elem);
std::for_each(Container.begin(), Container.end(), CountAllWhoShouldBe);
std::cout << CountAllWhoShouldBe.getCounter() << " items should be counted." << std::endl;
getchar();
}
Question is
So Do functors maintain state of their objects by themselves, i.e. without needing any reference variables as shown in example 2
Or Code in Example 1 is working because std::generate() calls the functor by reference/pointer?
Further reading material appreciated.
When you call
std::generate, it gets its own copy of the functor object. Once inside that function though, it’s just calling it’s own single instance of the object repeatedly, so state is preserved inside thegeneratecall, but not betweengenerateand the caller.So, change your code to
and afterwards
v1.nwill still be zero. Insidegenerateit was operating on its local copy (say v2), which did get incremented, but couldn’t tell v1 about it.Now, if you want to communicate v2’s state out to v1, that’s when you need to use references inside your functor, so v1 and v2 share whatever state gets mutated inside the call.
We can expand the call to show this more clearly:
Now it should be obvious that if
v1, instead of being a value object which gets deep-copied and keeps its state internally, kept a reference to shared state and was shallow copied, thenv2would share the same state asv1and that state would be accessible after the call.In fact, we can write a simple-ish wrapper to automate this, so you don’t need to do it by hand for every functor:
Now changing the original code to:
means
v1.iwill be updated in place.As Jerry Coffin points out, preservation of state even inside the call isn’t guaranteed, so it’s sensible to do something like this with stateful functors even if you don’t need the state preserved for the caller.