1

我的 remove_if 似乎正在用过滤掉的元素的值覆盖未过滤掉的元素。这些代码的目的是允许用户过滤和仅显示某个类别的教师。(不删除任何元素)这是一些代码

static string compare;
static string debug;

bool filter_Cat (Teacher &t) 
{ 
    return (t.getCat() != compare); 
}

void filterCat (vector<Teacher> &t)
{
   vector<Teacher>::iterator i;
   vector<Teacher>::iterator newedited = remove_if(t.begin(), t.end(), filter_Cat);
   for (i = t.begin(); i != newedited; ++i)
   {
     Teacher& te = *i;
     te.getName();
     cout << "\t";
     te.getCategory();
     cout << "\t";
     te.getLocation();
   }
 }

 void filterTutorCat(vector<Teacher> &t)
 {
    int choice;
    cout << "No\tCategory" << endl
         << "1\tEnglish" << endl
         << "2\tMath" << endl
         << "3\tScience" << endl
         << "Choose the category you wish to filter :";
    cin >> choice;
    getline(cin, debug);

    if(choice <= 3 && choice > 0)
    {
        if (choice == 1)
        {
          compare = "English";
          filterCat(t);
        }
        if (choice == 2)
        {
          compare = "Math";
          filterCat(t);
        }
        if (choice == 3)
        {
          compare = "Science";
          filterCat(t);
        }

    }
    else
    {
        cout << "Invalid Option" << endl;
    }
 }
4

2 回答 2

2

remove_if将比较函数返回 false 的元素从右向左移动;换句话说,它用比较返回 false 的元素覆盖比较返回 true 的元素。但是,向量的大小不会改变。

这写着

从范围 [first, last) 中删除所有满足特定条件的元素。第一个版本删除所有等于 value 的元素,第二个版本删除所有谓词 p 返回 true 的元素。

删除是通过移动范围内的元素以覆盖要擦除的元素来完成的。范围的新旧两端之间的元素具有未指定的值。返回范围新结尾的迭代器。保留元素的相对顺序。

所以你想做的应该表达为:

void filterCat (vector<Teacher> &v)
{
   for (vector<Teacher>::iterator it = v.begin(); it != v.end() ; ++it)
   {
      if (!filter_Cat(*i))
      {
           std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
      }
   }
 }

似乎在您的代码中,getName()打印了理想情况下不应执行的名称,而是应返回名称。因此,我建议您对其进行更改以使其返回名称。并且做同样的事情getCategory。正确选择你的名字。如果是getName(),您应该通过返回它来获取您的姓名;如果是printName(),那么它应该打印名称。


此外,您编写的代码也不好:

  • 您应该避免使用全局变量。
  • 您应该尽可能避免使用 if-else。学习更好的方法。
  • 您应该了解函数对象(或函子)
  • 您应该了解const成员函数。
  • 您应该了解 和 之间的区别iteratorconst_iterator以及它们的用法。
  • 您应该了解 const 引用和非 const 引用之间的区别。并尝试适当地使用它们。

所以我会把你的代码写成:

//this is functor, not a function
struct filter_cat
{
   std::string m_cat; //use member data, avoid global variable
   filter_cat(std::string const & cat) : m_cat(cat) {}
   bool operator()(Teacher const & t) const  //const member function
   { 
     return (t.getCat() != m_cat); //getCat should be const member function
   }
};

//pass vector by const reference
void filterCat (vector<Teacher> const & v, filter_cat filter)
{
   //use const_iterator here, instead of iterator 
   for (vector<Teacher>::const_iterator it = v.begin(); it != v.end() ; ++it)
   {
      if (!filter(*i))
      {
           //getName and getCategory should be const member function
           std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
      }
   }
}

void filterTutorCat(vector<Teacher> const &t)
{
    int choice;
    cout << "No\tCategory" << endl
         << "1\tEnglish" << endl
         << "2\tMath" << endl
         << "3\tScience" << endl
         << "Choose the category you wish to filter :";
    cin >> choice;
    getline(cin, debug);

    //avoid if-else as much as possible, learn better ways!
    std::string cats[] = {"English", "Math", "Science"};

    if(choice <= 3 && choice > 0)
    {
          filterCat(v, filter_cat(cats[choice-1]));
    }
    else
    {
        cout << "Invalid Option" << endl;
    }
}

如评论中所述:getCat,getNamegetCategory应该是 const 成员函数。实际上,如果getCategory返回类别,则getCat甚至不需要。

解决了我的问题。

于 2012-01-21T06:15:37.057 回答
1

remove_if 收集 filter_Cat 在容器开始时返回 false 的值。虽然它不会减少容器中的元素数量,但它也不会对超出返回范围的元素值做出任何保证。所以你在使用 remove_if 时会失去价值。

于 2012-01-21T06:12:33.450 回答