2012-05-09 4 views
5

У меня есть функция, которая возвращает итератор, если объект найден.возвращающие итераторы C++

Теперь у меня есть проблема. Как я могу исправить проблему информирования объекта, который вызвал эту функцию, чтобы объект не был найден?

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? 

} 

Нужно ли мне вместо этого изменить структуру данных?

Заранее благодарен! :)

+2

Если у вас нет особых причин использовать свои собственные, рассмотрите 'std :: find'. Способ, которым он реализован, заключается в том, что он вернет 'end()'. – chris

+2

Это похоже на дефект дизайна. Верните копию, указатель, bool, указывающий найденный статус, и измените экземпляр ввода через ссылку, но НЕ возвращайте итератор в скрытый контейнер! –

+0

найти сложность O (n). Я действительно использую двоичный поиск в конце, чтобы выполнить поиск. Это важно, поскольку я внедряю очень огромную распределенную систему. – mister

ответ

0

Не возвращайте итератор в скрытый контейнер. Верните просто то, что вы хотите, а именно средство доступа к объекту, если оно существует. В этом примере я храню объекты в контейнере с помощью указателя.Если ваши объекты существуют только временно, то новый и скопируйте объект!

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 
} 

редактировать: умный, что нужно сделать, это написать компаратор для вашего класса и использовать алгоритмы СТД рода и найти их для вас. Однако делайте то, что хотите.

+0

Мне бы хотелось, если бы вы рекомендовали использовать общие указатели. Представляя грубые указатели, у меня болят мои чувства. –

+0

Мой опыт работы с общими/умными указателями не был хорош в целом. Это находит для кода, изолированного внутри ваших собственных классов, но то, что происходит со мной (по крайней мере, в моих проектах), заключается в том, что я сталкиваюсь с проблемами, когда интерфейсы кода должны взаимодействовать друг с другом и в любом случае нуждаются в необработанном указателе. Кроме того, вы просите, чтобы объекты жили дольше, чем они должны, или в непоследовательных состояниях, потому что порядок уничтожения не так прост в управлении. Мне проще просто инкапсулировать указатели и сделать его известным «это мое», вы заимствуете его. Не храните его. Спросите меня, прежде чем использовать его ». –

+0

Не сдавайтесь! Ваш пример звучит как работа для [std :: weak_ptr] (http://en.cppreference.com/w/cpp/memory/weak_ptr). На мой взгляд, использование интеллектуальных указателей любого типа - это почти всегда путь - подумайте о безопасности исключений ([RAII] (http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)) для одного. Я согласен с тем, что при работе с интерфейсами вы можете получить hosed, особенно если интерфейсы относятся к другому продукту/API, и у вас нет контроля. Но это все еще стоит того, для меня. –

5

Вы можете вернуть итератор в конец, то есть return class.vecCont.end(), чтобы указать это.

7

Возвращение vector::end(), бросить исключение или вернуть что-то иное, чем обычный итератор

еще лучше, не реализовать свою собственную Find функции. Для этого нужна библиотека <algorithm>. На основе вашего psudocode вы, вероятно, можете использовать std::find или std::find_if. find_if особенно полезен в случаях, когда равенство необязательно означает operator==. В этих случаях вы можете использовать lambda [C++ 11] или если 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(), если этот человек WASN Не нашел.

C++ 11 лямбда - новый синтаксис языка, который делает этот процесс объявления/определения функтора и использования для многих случаев несколько проще. Это делается так:

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; }); 
+0

Я думаю, что исключение действительно правильный выбор, если итератор невозможен. (Например, поскольку вызывающий объект не знает, что он должен сравниваться с end(), или если это просто не отображается вызывающему.) – TaZ

1

Вы должны вернуть class.vecCont.end(), если объект не был найден. Но @chris прав - это именно то, для чего нужен std::find.

2

Как насчет того, чтобы просто вернуть конечный итератор?

Ваш код становится: -

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.

1

Что-то вроде этого

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

И не забудьте эти проверки на наличие вашего элемента или нет в контейнере

if (pos != coll.end()) 
0

Никогда не эмулировать std::algorithm функции внутри класса. Они являются свободными функциями по какой-то причине. Обычно этого достаточно, чтобы выставить begin и end функцию-член, которая возвращает правильные итераторы (и, возможно, boost::iterator_range). Если вам нужно сделать причудливую находку с функтором, выставляйте функтора.

Смежные вопросы