【问题标题】:Using an STL algorithm on vector of pointers of an object (C++)对对象的指针向量使用 STL 算法 (C++)
【发布时间】:2012-03-05 23:35:02
【问题描述】:

我需要计算指针数组的对象与赋予成员函数的参数具有相同名称(成员变量)的次数。我尝试了不同的方法,但都没有奏效。我的代码甚至没有编译。错误是:“error C2514: 'MyComparator' : class has no constructors”,这是我用于比较的类的代码和用于计算并发的函数。

 //definition of the vector
 vector<Class1*> files;
 ...
 int Class2::countNames(string name)
    {
       return count_if(files.begin(), files.end(), bind2nd(MyComparator(),name));
    }
 ...
class MyComparator{
public:
 bool operator()(const CFileType*& ob1, const string &str)
 {
   return ob1->getName()==str;
 }
};

我为此苦苦挣扎了好几个小时,我想用 STL 来做。这里的问题是我有一个指针向量,如果我有一个法线向量,它就不需要谓词函数,在我的情况下,我必须给它一个参数,我认为 bind2nd() 是正确的方法。任何帮助将不胜感激!

【问题讨论】:

    标签: c++ pointers vector countif bind2nd


    【解决方案1】:

    在 C++11 下,您可以使用 lambda 表达式,这比古老的 bind2nd 要容易得多。例如:

    #include <string>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    class Class1 {
    public:
        Class1(const std::string& name) : Name(name) {
        }
        const std::string& getName() const {
            return Name;
        }
    private:
        std::string Name;
    };
    
    size_t CountMatchingNames(const std::vector<Class1*>& v, const std::string& name) {
        return std::count_if(
            v.begin(),
            v.end(),
            [&name](Class1* c1) { return name == c1->getName(); }
        );
    }
    
    int main() {
    
        Class1 rob("rob");
        Class1 bob("bob");
        Class1 mitch("mitch");
    
        std::vector<Class1*> v;
        v.push_back(&bob);
        v.push_back(&mitch);
        v.push_back(&rob);
        v.push_back(&mitch);
        v.push_back(&bob);
        v.push_back(&bob);
    
        std::cout << "rob count:\t" << CountMatchingNames(v, "rob") << std::endl;
        std::cout << "bob count:\t" << CountMatchingNames(v, "bob") << std::endl;
        std::cout << "mitch count:\t" << CountMatchingNames(v, "mitch") << std::endl;
    
        return EXIT_SUCCESS;
    
    }
    

    打印出来:

    rob count:      1
    bob count:      3
    mitch count:    2
    

    【讨论】:

    • 非常感谢,完美运行,而且比使用 bold bind2nd() bold 更紧凑
    • @Goshutu 我忘了通过引用传递向量(请参阅编辑)。这不会影响正确性,但会影响性能,因为不再需要在每次调用 CountMatchingNames 时复制向量。
    • 没问题,因为这是一个类的成员函数
    【解决方案2】:

    首先,您需要确保在使用它时知道您的比较类:将MyComparator 的定义移到countNames() 的定义前面是我的第一步。也就是说,bind2nd() 想知道它处理的函数对象比你提供的要好一点:它通常想知道result_type、first_argument_type 和second_argument_type。您可以通过std::binary_function&lt;bool, CFileType const*, std::string const&amp;&gt; 或通过显式定义它们来获取它们。尽管我认为这不是必需的,但您可能希望将函数调用运算符设为const。另一方面,如果你定义的是一个函数对象而不是一个函数(你可以使用std::ptr_fun()获得必要的typedefs;我个人认为这个名字是为了让这些人有吸引力,因为它肯定不是'当你必须使用它们时没有太多乐趣),你可以一直走下去,而不是首先干涉活页夹:

    class MyComparator {
    public:
        MyComparator(std::string const& value): value_(value) {}
        bool operator()(CFileType const* obj) const {
            return obj->getName() == this->value_;
        }
    private:
        std::string value_;
    };
    ...
    std::count_if(files.begin(), files.end(), MyComparator(name));
    

    在定义函数并绑定它时,使用绑定器可以获得大致相同的效果。通常,当我不尝试代码时会出错,但它看起来像这样:

    bool myComparator(CFileType const* obj, std::string name) {
        return obj->getName() == name;
    }
    ...
    std::count_if(files.begin(), files.end(),
                  std::bind2nd(std::ptr_fun(myComparator), name));
    

    如果您想通过引用传递 name 参数而不是一直复制它,您将无法使用 std::bind2nd(),至少除非您使用 C++ 2011 编译器:否则创建一个具有连续的const 编译器不喜欢的关键字的类型。您可以使用例如boost::bind()没有这个问题:

    std::count_if(files.begin(), files.end(), boost::bind(myComparator, _1, name));
    

    ...并将name 参数的声明更改为std::string const&amp; name。

    【讨论】:

      【解决方案3】:

      但是,原则上你的想法是可行的:

      1. 比较器类必须在使用前定义;
      2. 它必须继承自 binary_function 以包含必要的 typedef;
      3. 它的operator() 需要声明为const。

      通过这些更正,以下示例适用于我:

      #include <vector>
      #include <functional>
      #include <string>
      #include <algorithm>
      #include <iostream>
      
      using namespace std;
      
      struct Class1 {
        string getName() const { return "aaa"; }
      };
      
      //...
      class MyComparator: public binary_function<const Class1*, string, bool> {
      public:
       bool operator()(const Class1* ob1, const string &str) const
       {
         return ob1->getName()==str;
       }
      };
      
      vector<Class1*> files;
      //...
       int countNames(string name)
          {
             return count_if(files.begin(), files.end(), bind2nd(MyComparator(),name));
          }
      
      int main() {
        files.push_back(new Class1);
        files.push_back(new Class1);
        cout << countNames("aaa") << ' ' << countNames("bbb") << endl;
      }
      

      但是,请注意,拥有一个指针向量很容易导致内存泄漏(如我的示例中所示)。考虑使用 Boost.PointerContainer 或(使用 C++11)unique_ptrs 的容器。

      【讨论】:

      • 我已经尝试过这种方法,但没有成功,出现了同样的错误信息,虽然,“Branko Dimitrijevic”的答案有效,我的程序现在运行良好!
      【解决方案4】:

      这里有几个问题:

      • 看起来您在使用MyComparator 后定义了它。使用前需要定义类型。
      • 向量包含Class1*,但比较器使用CFileType*。
      • 不推荐使用的bind1st 和bind2nd 使用起来有点棘手,并且需要函数类型定义各种类型。假设您不能使用新的std::bind(或boost::bind),最简单的解决方法是让MyComparator 继承自std::binary_function&lt;Class1*, string, bool&gt;
      • operator() 需要声明为const。

      如果您的编译器支持 C++11,那么您可以更简单地使用 std::bind 或 lambda:

      count_if(files.begin(), files.end(), bind(MyComparator(), placeholders::_1, name));
      

      或

      count_if(files.begin(), files.end(), [&name](Class1 const * p){return p->getName()==name;});
      

      【讨论】:

        猜你喜欢
        • 2011-10-01
        • 2011-02-11
        • 1970-01-01
        • 2010-12-20
        • 2014-01-02
        • 2012-02-02
        • 1970-01-01
        • 2012-07-15
        • 2013-03-14
        相关资源
        最近更新 更多