std :: for_each,带有operator()的对象重载不维护状态

时间:2011-08-11 10:19:52

标签: c++ visual-studio-2008 std

在尝试回答this问题时,我提出了以下代码:

#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;
}

调试它会显示正在调用Sizes :: operator(),并且sizeVec的大小随着每个调用的增加而增加。然而,当第二个std :: foreach被调用时,sizeVec是空的...我创建了一个涉及将向量传递给Sizes的工作,但有人知道发生了什么

3 个答案:

答案 0 :(得分:3)

std::for_each按值获取仿函数,而不是参考,因此原始对象不受影响。你需要这样做:

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

答案 1 :(得分:2)

下面显示的代码段引自您的代码,就像我写这篇文章时那样。

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

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

v按值传递,这可能效率很低!通过引用传递它。


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

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

_tmain从未成为main的有效形式。

此代码最多只能与Microsoft的编译器一起编译。

此外,_tmain即使使用Microsoft的编译器也没有用处,除了针对Windows 9x的一个特殊情况(一般情况下甚至不针对Windows 9x)。

为什么要编写 more 以便为非Windows程序员呈现非标准和不可编码的代码?

使用标准main


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

>>可能会编译大多数现代编译器,因为它们支持即将推出的C ++ 0x。但是在C ++ 98 / C ++ 03中它无效。所以,仍然,对于可移植代码,请写> >(注意空格)。


    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可以在这里自由复制,实际上是按值传递的。

但是,std::for_each会返回最终结果的副本。

您可以将其分配回sizes,即使在仿函数包含向量时这是一种非常低效的处理方式。


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

    return 0;

对于标准return 0;,此最终main不是必需的,因为它仅表示标准main的默认返回值。


}

干杯&amp;第h

答案 2 :(得分:2)

我会做一些不同的事情:

// (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.

您的第二个for_each和outFunc()可以替换为一些标准对象:

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

一个次要但更加模糊的注释,通过将状态保持在Sizes对象之外,可以在明年到达时更容易转换为C ++ 0x lambda:

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()); }
             );