web-dev-qa-db-fra.com

Renvoyer un pointeur sur un élément vectoriel en c ++

J'ai un vecteur de myObjects dans la portée globale . J'ai une méthode qui utilise un std::vector<myObject>::const_iterator pour parcourir le vecteur et faire des comparaisons pour trouver un élément spécifique . Une fois que j'ai trouvé l'élément requis, je veux pouvoir y retourner un pointeur (le vecteur existe dans sa portée globale).

Si je retourne &iterator, est-ce que je retourne l'adresse de l'itérateur ou l'adresse de ce que l'itérateur pointe?

Dois-je convertir le const_iterator dans un myObject, puis en retourner l'adresse?

57
Krakkos

Renvoie l'adresse de la chose indiquée par l'itérateur:

&(*iterator)

Edit: Pour dissiper une certaine confusion:

vector <int> vec;          // a global vector of ints

void f() {
   vec.Push_back( 1 );    // add to the global vector
   vector <int>::iterator it = vec.begin();
   * it = 2;              // change what was 1 to 2
   int * p = &(*it);      // get pointer to first element
   * p = 3;               // change what was 2 to 3
}

Pas besoin de vecteurs de pointeurs ou d'allocation dynamique.

81
anon

Renvoyer et itérateur renverra l'adresse de l'itérateur. Si vous voulez renvoyer une manière de faire référence à l'élément, retournez l'itérateur lui-même.

Attention, vous n'avez pas besoin que le vecteur soit global pour renvoyer l'itérateur/pointeur, mais que les opérations dans le vecteur peuvent invalider l'itérateur. L'ajout d'éléments au vecteur, par exemple, peut déplacer les éléments vectoriels vers une position différente si la nouvelle taille () est supérieure à la mémoire réservée. La suppression d'un élément avant l'élément donné du vecteur obligera l'itérateur à se référer à un élément différent.

Dans les deux cas, selon l'implémentation de la STL, il peut être difficile de déboguer, des erreurs aléatoires se produisent si souvent.

EDIT après commentaire: 'oui, je ne voulais pas renvoyer l'itérateur a) car il est constant, et b) ce n'est sûrement qu'un itérateur local et temporaire? - Krakkos '

Les itérateurs ne sont ni plus ni moins locaux ou temporaires que toute autre variable et ils sont copiables. Vous pouvez le retourner et le compilateur fera la copie pour vous comme il le fera avec le pointeur.

Maintenant avec la const-ness. Si l'appelant souhaite effectuer des modifications via l'élément renvoyé (qu'il s'agisse d'un pointeur ou d'un itérateur), vous devez utiliser un itérateur non const. (Supprimez simplement le 'const_' de la définition de l'itérateur).

Ce n'est pas une bonne idée de retourner des itérateurs. Les itérateurs deviennent invalides lorsque des modifications du vecteur (inversion\suppression) sont effectuées. En outre, l'itérateur est un objet local créé sur une pile. Par conséquent, renvoyer l'adresse de celui-ci n'est pas du tout sécurisé. Je vous suggérerais de travailler avec myObject plutôt qu'avec des itérateurs vectoriels.

EDIT: Si l’objet est léger, il est préférable de le renvoyer lui-même. Sinon, renvoyez les pointeurs vers myObject stockés dans le vecteur.

3
aJ.

Tant que votre vecteur reste dans la portée globale, vous pouvez retourner:

&(*iterator)

Je vous préviens que c'est assez dangereux en général. Si votre vecteur quitte sa portée globale et est détruit, tous les pointeurs vers myObject deviennent invalides. Si vous écrivez ces fonctions dans le cadre d'un projet plus vaste, le renvoi d'un pointeur non-const peut amener quelqu'un à supprimer la valeur renvoyée. Cela aura des effets non définis et catastrophiques sur l'application. 

Je réécrirais ceci en tant que:

myObject myFunction(const vector<myObject>& objects)
{
    // find the object in question and return a copy
    return *iterator;
}

Si vous devez modifier le myObject renvoyé, stockez vos valeurs sous forme de pointeurs et allouez-les sur le tas:

myObject* myFunction(const vector<myObject*>& objects)
{
    return *iterator;
}

De cette façon, vous contrôlez quand ils sont détruits.

Quelque chose comme ça va casser votre application:

g_vector<tmpClass> myVector;

    tmpClass t;
    t.i = 30;
    myVector.Push_back(t);

    // my function returns a pointer to a value in myVector
    std::auto_ptr<tmpClass> t2(myFunction());
3
Aaron Saarela

Vous pouvez utiliser la fonction data du vecteur:

Renvoie un pointeur sur le premier élément du vecteur.

Si vous ne voulez pas que le pointeur sur le premier élément, mais par index, vous pouvez essayer, par exemple:

//the index to the element that you want to receive its pointer:
int i = n; //(n is whatever integer you want)

std::vector<myObject> vec;
myObject* ptr_to_first = vec.data();

//or

std::vector<myObject>* vec;
myObject* ptr_to_first = vec->data();

//then

myObject element = ptr_to_first[i]; //element at index i
myObject* ptr_to_element = &element;

Vous stockez les copies de myObject dans le vecteur. Je pense donc que copier l'instance de myObject n'est pas une opération coûteuse. Ensuite, je pense que le plus sûr serait de retourner une copie de myObject depuis votre fonction.

0
Naveen

Dis, tu as ce qui suit:

std::vector<myObject>::const_iterator first = vObj.begin();

Alors le premier objet du vecteur est: *first. Pour obtenir l'adresse, utilisez: &(*first).

Cependant, en accord avec la conception STL, je suggérerais de renvoyer un itérateur si vous prévoyez de le transmettre ultérieurement aux algorithmes STL.

0
dirkgently

Reportez-vous aux réponses de dirkgently et anon, vous pouvez appeler la fonction avant au lieu de begin fonction, de sorte que vous devez pas écrire le *, mais uniquement le &.

Exemple de code:

vector<myObject> vec; //You have a vector of your objects
myObject first = vec.front(); //returns reference, not iterator, to the first object in the vector so you had only to write the data type in the generic of your vector, i.e. myObject, and not all the iterator stuff and the vector again and :: of course
myObject* pointer_to_first_object = &first; //* between & and first is not there anymore, first is already the first object, not iterator to it.

Je ne suis pas sûr qu'il soit nécessaire de renvoyer l'adresse de la chose indiquée par l'itérateur . Vous verrez que la classe itérateur de STL elle-même implémente l'utilisation de _Ptr à cette fin. Alors, faites juste:

return iterator._Ptr;
0
arviman