std::for_each, object with operator() overloaded not maintaining state

醉酒当歌 提交于 2019-12-08 10:06:57

问题


In trying to answer this question I came up with the following code:

#include <string>
#include <iostream> 
#include <algorithm>
#include <vector>

class Sizes
{
public:
    void operator() ( std::vector<int> v ) { 
        sizeVec.push_back( v.size() );  
    }
    std::vector<int> sizeVec;
};

void outFunc (int i) {
    std::cout << " " << i;
}
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<std::vector<int>> twodVec;

    std::vector<int> vec;
    vec.push_back( 6 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );
    vec.push_back( 8 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );

    Sizes sizes;
    std::for_each( twodVec.begin(), twodVec.end(), sizes );
    std::for_each( sizes.sizeVec.begin(), sizes.sizeVec.end(), outFunc );

    return 0;
}

Debugging this shows Sizes::operator() being called and the size of sizeVec increasing with each call as expected. However when the second std::foreach is called the sizeVec is empty... I've created a work around involving passing a vector into Sizes but does anyone know what's going on


回答1:


std::for_each takes a functor by value, not by reference, so the original object is unaffected. You need to do:

sizes = std::for_each( twodVec.begin(), twodVec.end(), sizes );



回答2:


The code snippets shown below are quoted from your code as it was when I wrote this.

#include <string>
#include <iostream> 
#include <algorithm>
#include <vector>

class Sizes
{
public:
    void operator() ( std::vector<int> v ) { 

v is passed by value, which can be pretty inefficient! Pass it by reference.


        sizeVec.push_back( v.size() );  
    }
    std::vector<int> sizeVec;
};

void outFunc (int i) {
    std::cout << " " << i;
}
int _tmain(int argc, _TCHAR* argv[])

_tmain has never been a valid form of main.

This code will, at best, only compile with Microsoft's compiler.

Also, _tmain has no purpose even with Microsoft's compiler, except for one special case when targeting Windows 9x (not even for targeting Windows 9x in general).

Why are you writing more in order to render your code non-standard and ungrokkable for non-Windows programmers?

Use standard main.


{
    std::vector<std::vector<int>> twodVec;

The >> will probably compile with most modern compilers, due to their support for the upcoming C++0x. But in C++98/C++03 it is invalid. So, still, for portable code write > > (note the space).


    std::vector<int> vec;
    vec.push_back( 6 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );
    vec.push_back( 8 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );

    Sizes sizes;
    std::for_each( twodVec.begin(), twodVec.end(), sizes );

sizes can be freely copied here, and is in fact passed by value.

However, std::for_each returns a copy of the final result.

You can assign that back to sizes, even if it is a quite inefficient way of doing things when the functor contains a vector.


    std::for_each( sizes.sizeVec.begin(), sizes.sizeVec.end(), outFunc );

    return 0;

This final return 0; is not necessary with a standard main, since it only expresses the default return value for standard main.


}

Cheers & hth.




回答3:


I would do a couple of things differently:

// (1) struct rather than class for functor (as it contains no state).
struct Sizes
{
    // (2) Keep a reference to the vector
    std::vector<int>&    sizeVec;

    Sizes(std::vector<int>& sizeVec): sizeVec(sizeVec) {}

    // (3) The functor can now be const as the the state is external
    void operator() ( std::vector<int> const& v ) const
    {                              //  ^^^^^^  (4) Pass parameter by const reference
                                   //              This avoids an unnecessary copy.
        sizeVec.push_back( v.size() );  
    }
};

std::for_each( twodVec.begin(), twodVec.end(), Sizes(vec) );
                                         //    ^^^^^^^^^^  Call using temporary
                                         //                No need for a Size variable.

Your second for_each and outFunc() can be replaced with some standard objects:

std::copy(sizes.sizeVec.begin(),
          sizes.sizeVec.end(),
          std::ostream_iterator<int>(std::cout, " ")
         );

A secondary though more obscure note, By keeping state out of the Sizes object makes it easier to convert to C++0x lambda when this arrives next year:

std::for_each( twodVec.begin(), twodVec.end(), Sizes(vec) );

// becomes

std::for_each( twodVec.begin(),
               twodVec.end(), 
               [&vec] ( std::vector<int> const& v ) {  vec.push_back(v.size()); }
             );


来源:https://stackoverflow.com/questions/7024198/stdfor-each-object-with-operator-overloaded-not-maintaining-state

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!