2012-05-09 38 views
5

Tengo una función que devuelve un iterador si se encuentra un objeto.devolver iteradores de C++

Ahora tengo un problema. ¿Cómo soluciono el problema de informar al objeto que llamó a esta función que no se encontró el objeto?

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? 

} 

¿Debo cambiar mi estructura de datos en este lugar?

¡Gracias de antemano! :)

+2

Si no tiene un motivo en particular para usar el suyo, considere 'std :: find'. Sin embargo, la forma en que se implementó es que devolvería 'end()'. – chris

+2

Esto simplemente parece un defecto de diseño. Devuelve una copia, un puntero, un bool que indica el estado encontrado y modifica una instancia de entrada por referencia, ¡pero NO devuelve un iterador a un contenedor oculto! –

+0

encontrar la complejidad es O (n). De hecho, estoy usando una búsqueda binaria de back-end para hacer la búsqueda. Esto es importante ya que estoy implementando un sistema distribuido muy grande. – mister

Respuesta

0

No devuelva un iterador a un contenedor oculto. Regrese simplemente qué es lo que quiere, es decir, un medio para acceder a un objeto si existe. En este ejemplo, almaceno los objetos en el contenedor a través de un puntero.¡Si sus objetos solo existen temporalmente, entonces uno nuevo y copie el objeto!

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 
} 

edición: la cosa inteligente que hacer es escribir un comparador para su clase y utilizar el std algoritmos de clasificación y para encontrarlos para usted. Sin embargo, haz lo que quieras.

+0

Me gustaría que esto ocurriera si hubiera recomendado el uso de punteros compartidos. La introducción de punteros crudos aquí hiere mis sentimientos. –

+0

Mi experiencia con punteros compartidos/inteligentes no ha sido buena en general. Es encontrar código aislado dentro de sus propias clases, pero lo que me sucede (al menos en mis proyectos) es que me encuentro con problemas cuando las interfaces de códigos necesitan comunicarse entre sí y necesitan un puntero sin procesar de todos modos. Además, pides que los objetos vivan más de lo que deberían o en estados incoherentes porque el orden de destrucción no es tan fácil de controlar. Me resulta más sencillo simplemente encapsular punteros y dar a conocer que "esto es mío. Solo lo estás pidiendo prestado. No lo almacenes. Pregúntame antes de usarlo". –

+0

¡No te rindas! Su ejemplo parece un trabajo para [std :: weak_ptr] (http://en.cppreference.com/w/cpp/memory/weak_ptr). En mi opinión, el uso de punteros inteligentes de cualquier tipo es casi siempre el camino a seguir, piense en la seguridad de excepciones ([RAII] (http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)) para uno. Estoy de acuerdo en que cuando trabajas con interfaces, es posible que te manguen con una manguera, especialmente si las interfaces son para otro producto/API y no tienes control. Pero todavía vale la pena, para mí. –

5

Puede devolver un iterador hasta el final, es decir, return class.vecCont.end() para indicarlo.

7

Volver vector::end(), lanzar una excepción, o devolver algo más que un iterador llanura

Mejor aún, no implementar su propia función Find. Para eso está la biblioteca <algorithm>. Según su psudocódigo, probablemente pueda usar std::find o std::find_if. find_if es particularmente útil en casos donde la igualdad no significa necesariamente operator==. En esos casos, puede usar un lambda [C++ 11] o si C++ 11 no está disponible para usted, una clase ficticia.

Desde el funtor es el denominador común más bajo, voy a empezar con eso:

#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 ahora apunta a la persona cuyo nombre es "John Doe", o bien puntos de people_.end() si esa persona wasn no encontrado.

A C++ 11 lambda es la nueva sintaxis del lenguaje que hace que este proceso de declaración/definición de un funtor sea algo más simple en muchos casos. Se hace así:

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

Creo que una excepción es la opción correcta si un iterador no es posible. (Por ejemplo, porque la persona que llama no sabe que debe comparar con end() o si esto simplemente no es visible para la persona que llama.) – TaZ

1

Debe volver class.vecCont.end() si no se encontró el objeto. Pero @chris tiene razón, esto es exactamente para lo que es std::find.

2

¿Qué le parece devolver el iterador final?

Su código se convierte en: -

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

o simplemente utilizar std::find.

1

Algo como esto

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

Y no se olvide de estos controles para detectar la presencia del elemento o no en el contenedor

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

Nunca emular std::algorithm funciones dentro de una clase. Son funciones gratuitas por una razón. Por lo general, es suficiente para exponer begin y end función de miembro que devuelve los iteradores correctos (y posiblemente un boost::iterator_range). Si necesita hacer un hallazgo elegante con un funtor, exponga también el funtor.