web-dev-qa-db-fra.com

Convertir un itérateur en pointeur?

J'ai un std::vector avec des éléments n. Maintenant, je dois passer un pointeur sur un vecteur contenant les derniers éléments n-1 dans une fonction.

Par exemple, mon vector<int> foo contient (5,2,6,87,251). Une fonction prend vector<int>* et je veux lui passer un pointeur sur (2,6,87,251).

Puis-je simplement (en toute sécurité) prendre l'itérateur ++foo.begin(), le convertir en pointeur et le transmettre à la fonction? Ou utilisez &foo[1]?

UPDATE: Les gens me suggèrent de changer de fonction pour prendre un itérateur plutôt qu'un pointeur. Cela ne semble pas possible dans mon cas, puisque la fonction que j'ai mentionnée est la fonction find de unordered_set<std::vector*>. Donc, dans ce cas, est-ce que copier les éléments n-1 de foo dans un nouveau vecteur et appeler find avec un pointeur sur la seule option? Très inefficace! C'est comme Shlemiel le peintre, surtout depuis que je dois interroger de nombreux sous-ensembles: les derniers éléments n-1, puis n-2, etc. et voir s'ils se trouvent dans le unordered_set.

40
Frank

Cela semble impossible dans ma situation, puisque la fonction que j'ai mentionnée est la fonction de recherche de unordered_set<std::vector*>

Utilisez-vous des objets de fonction de hachage/prédicat personnalisés? Si ce n'est pas le cas, vous devez alors transmettre unordered_set<std::vector<int>*>::find() le pointeur au vecteur exact que vous souhaitez rechercher. Un pointeur sur un autre vecteur avec le même contenu ne fonctionnera pas. Ce n'est pas très utile pour les recherches, c'est le moins qu'on puisse dire. 

Il serait préférable d’utiliser unordered_set<std::vector<int> > car vous pourrez alors effectuer des recherches par valeur. Je pense que cela nécessiterait également un objet de fonction de hachage personnalisé car hash n’a pas, à ma connaissance, de spécialisation pour vector<int>.

Quoi qu'il en soit, un pointeur au milieu d'un vecteur n'est pas en soi un vecteur, comme d'autres l'ont expliqué. Vous ne pouvez pas convertir un itérateur en pointeur en vecteur sans copier son contenu.

8
bk1e

le voici, obtenant une référence au pointeur correspondant d'un itérateur utilisé: 

exemple:

string my_str= "hello world";

string::iterator it(my_str.begin());

char* pointer_inside_buffer=&(*it); //<--

[notifier l'opérateur * retourne une référence donc faire & sur une référence vous donnera l'adresse].

77
Robocide

Si vous le pouvez, un meilleur choix peut être de changer la fonction pour prendre un itérateur en élément ou un nouveau vecteur (s'il ne le modifie pas).

Bien que vous puissiez faire ce genre de choses avec des tableaux puisque vous savez comment ils sont stockés, il est probablement une mauvaise idée de faire la même chose avec des vecteurs. &foo[1] n'a pas le type vector<int>*.

De plus, bien que l'implémentation STL soit disponible en ligne, il est généralement risqué d'essayer de s'appuyer sur la structure interne d'une abstraction.

6
Uri

Un vecteur est un conteneur avec la pleine propriété de ses éléments. Un vecteur ne peut pas avoir une vue partielle d'un autre, même une vue const. C'est la cause fondamentale ici. 

Si vous en avez besoin, créez votre propre conteneur contenant des vues avec des données faibles pour les données ou consultez des plages. Paire d'itérateurs (même les pointeurs fonctionnent bien en tant qu'itérateurs dans un vecteur) ou, mieux encore, boost :: iterator_range qui fonctionnent de manière parfaitement transparente.

Cela dépend de la modularité de votre code. Utilisez std :: pair si vous devez masquer le code dans un cpp.

3
Macke

Votre fonction ne devrait pas prendre vector<int>*; Il devrait prendre vector<int>::iterator ou vector<int>::const_iterator selon le cas. Ensuite, passez simplement dans foo.begin() + 1.

3
Chris Jester-Young

La réponse directe à votre question est oui. Si foo est un vecteur, vous pouvez faire ceci: & foo [1].

Cela ne fonctionne cependant que pour les vecteurs, car la norme indique que les vecteurs implémentent le stockage en utilisant une mémoire contiguë.

Mais vous pouvez toujours (et devriez probablement) passer des itérateurs au lieu d’indicateurs bruts car ils sont plus expressifs. Passer des itérateurs ne fait pas de copie du vecteur.

2
John Dibling

Par exemple, mon vector<int> foo contient (5,2,6,87,251). Une fonction prend vector<int>* et je veux lui passer un pointeur (2,6,87,251).

Un pointeur sur un vector<int> n'est pas du tout la même chose qu'un pointeur sur les éléments du vecteur.

Pour ce faire, vous devrez créer un nouveau vector<int> avec uniquement les éléments pour lesquels vous souhaitez qu'il passe un pointeur. Quelque chose comme:

 vector<int> tempVector( foo.begin()+1, foo.end());

 // now you can pass &tempVector to your function

Cependant, si votre fonction prend un pointeur sur un array of int, vous pouvez alors passer &foo[1].

1
Michael Burr

Utilisez vector::front , cela devrait être la solution la plus portable. Je l'ai utilisé lorsque je suis en interface avec une API fixe qui veut un caractère ptr. Exemple:

void funcThatTakesCharPtr(char* start, size_t size);

...

void myFunc(vector<char>& myVec)
{
    // Get a pointer to the front element of my vector:
    char* myDataPtr = &(myVec.front());

    // Pass that pointer to my external API:
    funcThatTakesCharPtr(myDataPtr, myVec.size());
}
1
Ogre Psalm33

Une version sûre pour convertir un itérateur en pointeur (exactement ce que cela signifie, quelles que soient les implications) et par safe, je ne veux pas craindre de déréférencer l'itérateur et de provoquer des exceptions/erreurs dues à end()/autres situations.

#include <iostream>
#include <vector>
#include <string.h>

int main()
{
    std::vector<int> vec;

    char itPtr[25];
    long long itPtrDec;

    std::vector<int>::iterator it = vec.begin();
    memset(&itPtr, 0, 25);
    sprintf(itPtr, "%llu", it);
    itPtrDec = atoll(itPtr);
    printf("it = 0x%X\n", itPtrDec);

    vec.Push_back(123);
    it = vec.begin();
    memset(&itPtr, 0, 25);
    sprintf(itPtr, "%llu", it);
    itPtrDec = atoll(itPtr);
    printf("it = 0x%X\n", itPtrDec);
}

imprimera quelque chose comme

il = 0x0

il = 0x2202E10

C'est une façon incroyablement astucieuse de le faire, mais si vous en avez besoin, cela fera l'affaire. Vous recevrez des avertissements du compilateur qui, si cela vous dérange vraiment, peuvent être supprimés avec #pragma

0
Shocker

Je n'ai pas testé cela, mais pourriez-vous utiliser un ensemble de paires d'itérateurs à la place? Chaque paire d'itérateurs représenterait les itérateurs de début et de fin du vecteur de séquence. Par exemple.:

typedef std::vector<int> Seq;
typedef std::pair<Seq::const_iterator, Seq::const_iterator> SeqRange;

bool operator< (const SeqRange& lhs, const SeqRange& rhs)
{
    Seq::const_iterator lhsNext = lhs.first;
    Seq::const_iterator rhsNext = rhs.first;

    while (lhsNext != lhs.second && rhsNext != rhs.second)
        if (*lhsNext < *rhsNext)
            return true;
        else if (*lhsNext > *rhsNext)
            return false;

    return false;
}

typedef std::set<SeqRange, std::less<SeqRange> > SeqSet;

Seq sequences;

void test (const SeqSet& seqSet, const SeqRange& seq)
{
    bool find = seqSet.find (seq) != seqSet.end ();
    bool find2 = seqSet.find (SeqRange (seq.first + 1, seq.second)) != seqSet.end ();
}

Il est évident que les vecteurs doivent être conservés ailleurs comme auparavant. De même, si un vecteur de séquence est modifié, son entrée dans l'ensemble devrait être supprimée et rajoutée, car les itérateurs pourraient avoir changé.

Jon

0
jon-hanson

Si votre fonction prend vraiment vector<int> * (un pointeur sur un vecteur), vous devez alors passer &foo car ce sera un pointeur sur le vecteur. Évidemment, cela ne résoudra pas simplement votre problème, mais vous ne pourrez pas convertir directement un itérateur en vecteur, car la mémoire située à l'adresse de l'itérateur n'adressera pas directement un vecteur valide.

Vous pouvez construire un nouveau vecteur en appelant le constructeur vector :

template <class InputIterator> vector(InputIterator, InputIterator)

Ceci construit un nouveau vecteur en copiant les éléments entre les deux itérateurs. Vous l'utiliseriez grossièrement comme ceci:

bar(std::vector<int>(foo.begin()+1, foo.end());
0
1800 INFORMATION

Vector est une classe de modèle et il n'est pas prudent de convertir le contenu d'une classe en un pointeur: Vous ne pouvez pas hériter de la classe de vecteur pour ajouter cette nouvelle fonctionnalité . Il est préférable de modifier le paramètre de fonction. Jst crée un autre vecteur de int Vecteur temp_foo (foo.begin [X], foo.end ()); Et passe ce vecteur à vos fonctions

0
vivek sapru