【问题标题】:returning c++ iterators返回 c++ 迭代器
【发布时间】:2012-05-09 19:30:37
【问题描述】:

如果找到一个对象,我有一个返回迭代器的函数。

现在我有一个问题。如何解决通知调用此函数的对象找不到对象的问题?

vector<obj>::iterator Find(int id, int test)
{
        vector<obj>::iterator it;
            aClass class;

            for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it)
            {
               if(found object) //currently in psuedo code
               return it;
            }

            return ???? // <<< if not found what to insert here?

}

我需要更改我的数据结构吗?

提前致谢! :)

【问题讨论】:

  • 如果您没有特别的理由使用自己的,请考虑std::find。不过,它的实现方式是返回end()
  • 这似乎是一个设计缺陷。返回副本、指针、指示找到状态的布尔值并通过引用修改输入实例,但不要将迭代器返回到隐藏容器!
  • 发现复杂度为 O(n)。我实际上正在使用后端二进制搜索来进行搜索。这很重要,因为我正在实现一个非常庞大的分布式系统。
  • @dupdupdup 但是该迭代器仅在容器未更改时才有效。这似乎是个坏主意。
  • 感谢艾亨德森!实际上那个临时解决了问题。但是,是的,圣哈辛托,你说的是真的。所以我希望你能给我一个例子来说明你之前的意思?

标签: c++ vector iterator


【解决方案1】:

返回vector::end(),抛出异常,或者返回非普通迭代器的东西

更好的是,不要实现自己的Find 函数。这就是&lt;algorithm&gt; 库的用途。根据您的伪代码,您可能可以使用std::findstd::find_iffind_if 在平等并不一定意味着 operator== 的情况下特别有用。在这些情况下,您可以使用 [C++11] lambda,或者如果您无法使用 C++11,则可以使用仿函数类。

由于函子是最小的公分母,我将从这个开始:

#include <cstdlib>
#include <string>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;

class Person
{
public:
    Person(const string& name, unsigned age) : name_(name), age_(age) {};

    string name_;
    unsigned age_;
};

class match_name : public unary_function <bool, string>
{
public:
  match_name(const string& rhs) : name_(rhs) {};
  bool operator()(const Person& rhs) const
  {
    return rhs.name_ == name_;
  }
private:
    string name_;
};

#include <iostream>

int main()
{
    vector<Person> people;
    people.push_back(Person("Hellen Keller", 99));
    people.push_back(Person("John Doe", 42));

    /** C++03 **/
    vector<Person>::const_iterator found_person = std::find_if( people.begin(), people.end(), match_name("John Doe"));

    if( found_person == people.end() )
        cout << "Not FOund";
    else
        cout << found_person->name_ << " is " << found_person->age_;
}

found_person 现在指向名为“John Doe”的人,如果找不到该人,则指向 people_.end()

C++11 lambda 是一种新的语言语法,它使得声明/定义函子和使用的过程在许多情况下更加简单。这样做是这样的:

string target = "John Doe";
vector<Person>::const_iterator found_person = std::find_if(people.begin(), people.end(), [&target](const Person& test) { return it->name_ == target; });

【讨论】:

  • 如果迭代器不可能,我认为异常确实是正确的选择。 (例如,因为调用者不知道它应该与 end() 进行比较,或者调用者根本看不到它。)
【解决方案2】:

您可以将迭代器返回到末尾,即return class.vecCont.end() 以表明这一点。

【讨论】:

    【解决方案3】:

    只返回结束迭代器怎么样?

    你的代码变成:-

    vector<obj>::iterator Find(int id, int test)
    {
       vector<obj>::iterator it;
       aClass class;
    
       for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it)
       {
         if(found object) //currently in psuedo code
           break;
       }
    
       return it;
    }
    

    或者只使用std::find

    【讨论】:

      【解决方案4】:

      如果找不到对象,您应该返回class.vecCont.end()。但@chris 是对的——这正是std::find 的用途。

      【讨论】:

        【解决方案5】:

        像这样的

        std::vector<obj>::iterator pos;
        pos = find(coll.begin(),coll.end(), val);
        

        别忘了检查你的元素是否存在于容器中

        if (pos != coll.end()) 
        

        【讨论】:

          【解决方案6】:

          不要将迭代器返回到隐藏容器。简单地返回您想要的,即访问对象(如果存在)的方法。在此示例中,我通过指针将对象存储在容器中。如果您的对象只是暂时存在,则新建一个并将对象复制过来!

          class AClass;
          
          //...some time later
          std::vector<AClass*> vecCont; //notice, store pointers in this example!
          
          //..some time later
          AClass * findAClass(int id, int test)
          {
            vector<AClass*>::iterator it;
          
            for(it = class.vecCont.begin(); it != class.vecCont.end(); ++it)
            {
               if(found object) //currently in psuedo code
               return it;
            }
          
            return NULL;
          }
          
          //later still..
          
          AClass *foundVal = findAClass(1, 0);
          if(foundVal)
          {
            //we found it!
          }
          else
          {
            //we didn't find it
          }
          

          编辑:明智的做法是为您的班级编写一个比较器并使用标准算法排序并为您找到它们。但是,做你想做的。

          【讨论】:

          • 如果您推荐使用共享指针,我会喜欢这个。在这里引入原始指针会伤害我的感受。
          • 我在共享/智能指针方面的经验总的来说并不好。它可以找到在您自己的类中隔离的代码,但是发生在我身上的事情(至少在我的项目中)是,当代码接口需要相互通信并且无论如何都需要原始指针时,我遇到了问题。此外,您请求对象的寿命比应有的时间长,否则会处于不一致的状态,因为销毁顺序不容易控制。我发现只封装指针并让它知道“这是我的。你只是借用它。不要存储它。在使用它之前征求我的许可。”
          • 不要放弃他们!您的示例听起来像是 std::weak_ptr 的工作。在我看来,使用任何类型的智能指针几乎总是可行的方法——想想异常安全 (RAII)。我同意在处理接口时您可能会感到厌烦,特别是如果接口是针对另一个产品/API 并且您无法控制时。但对我来说,这仍然是值得的。
          【解决方案7】:

          永远不要在类中模拟std::algorithm 函数。它们是免费功能是有原因的。通常暴露beginend 成员函数就足够了,它们返回正确的迭代器(可能还有boost::iterator_range)。如果您需要使用函子进行奇特的查找,请同时公开函子。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-09-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-23
            • 2018-02-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多