wake-up-neo.com

Iterator in Zeiger umwandeln?

Ich habe einen std::vector mit n Elementen. Jetzt muss ich einen Zeiger auf einen Vektor übergeben, der die letzten n-1-Elemente für eine Funktion enthält.

Mein vector<int> foo enthält beispielsweise (5,2,6,87,251). Eine Funktion nimmt vector<int>* und ich möchte einen Zeiger auf (2,6,87,251) übergeben.

Kann ich einfach (sicher) den Iterator ++foo.begin() nehmen, in einen Zeiger konvertieren und diesen an die Funktion übergeben? Oder benutze &foo[1]?

UPDATE: Die Leute schlagen vor, meine Funktion so zu ändern, dass ein Iterator anstelle eines Zeigers verwendet wird. Das scheint in meiner Situation nicht möglich zu sein, da die von mir erwähnte Funktion die find-Funktion von unordered_set<std::vector*> ist. Ist es in diesem Fall also das Kopieren der n-1-Elemente von foo in einen neuen Vektor und das Aufrufen von find mit einem Zeiger darauf die einzige Option? Sehr ineffizient! Es ist wie Shlemiel der Maler, vor allem, da ich viele Teilmengen abfragen muss: die letzten n-1-, dann n-2 usw. -Elemente und sehen, ob sie im unordered_set sind.

40
Frank

Das scheint in meiner Situation nicht möglich zu sein, da die Funktion, die ich erwähnt habe, die Suchfunktion von unordered_set<std::vector*> ist. 

Verwenden Sie benutzerdefinierte Hash-/Prädikat-Funktionsobjekte? Wenn nicht, müssen Sie unordered_set<std::vector<int>*>::find() den Zeiger an den genauen Vektor übergeben, den Sie suchen möchten. Ein Zeiger auf einen anderen Vektor mit demselben Inhalt wird nicht funktionieren. Dies ist nicht sehr nützlich für Suchvorgänge, um es gelinde auszudrücken. 

Die Verwendung von unordered_set<std::vector<int> > wäre besser, da Sie dann nach Wert suchen können. Ich denke, das würde auch ein benutzerdefiniertes Hash-Funktionsobjekt erfordern, da hash meines Wissens keine Spezialisierung für vector<int> hat.

In beiden Fällen ist ein Zeiger in die Mitte eines Vektors selbst kein Vektor, wie andere erklärt haben. Sie können einen Iterator nicht in einen Zeiger auf einen Vektor konvertieren, ohne dessen Inhalt zu kopieren.

8
bk1e

hier ist es, einen Verweis auf den entsprechenden Zeiger einer Iterator-Verwendung zu erhalten: 

beispiel:

string my_str= "hello world";

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

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

[Mitteilungsoperator * gibt einereferenz zurück & bei einer Referenz wird die Adresse angegeben].

77
Robocide

Wenn Sie können, besteht die bessere Möglichkeit darin, die Funktion so zu ändern, dass entweder ein Iterator zu einem Element oder ein brandneuer Vektor verwendet wird (wenn er sich nicht ändert).

Während Sie diese Art von Dingen mit Arrays ausführen können, da Sie wissen, wie sie gespeichert werden, ist es wahrscheinlich eine schlechte Idee, das Gleiche mit Vektoren zu tun. &foo[1] hat nicht den Typ vector<int>*.

Während die STL-Implementierung online verfügbar ist, ist es normalerweise riskant, sich auf die interne Struktur einer Abstraktion zu verlassen.

6
Uri

Ein Vektor ist ein Container mit vollem Besitz seiner Elemente. Ein Vektor kann keine Teilansicht eines anderen, auch keine const-Ansicht, enthalten. Das ist die Hauptursache hier. 

Wenn Sie das brauchen, erstellen Sie einen eigenen Container, der Ansichten mit weak_ptr's für die Daten enthält, oder sehen Sie sich die Bereiche an. Iteratorenpaare (sogar Zeiger funktionieren gut als Iteratoren in einen Vektor) oder, noch besser, boost :: iterator_range, die ziemlich nahtlos funktionieren.

Das hängt von der Vorlagefähigkeit Ihres Codes ab. Verwenden Sie std :: pair, wenn Sie den Code in einer CPP ausblenden müssen.

3
Macke

Ihre Funktion sollte vector<int>* nicht übernehmen. es sollte vector<int>::iterator oder vector<int>::const_iterator je nach Bedarf annehmen. Dann übergeben Sie einfach foo.begin() + 1.

3

Die direkte Antwort auf Ihre Frage lautet Ja. Wenn foo ein Vektor ist, können Sie Folgendes tun: & foo [1].

Dies funktioniert jedoch nur für Vektoren, da der Standard besagt, dass Vektoren den Speicher unter Verwendung von zusammenhängendem Speicher implementieren.

Aber Sie können (und sollten wahrscheinlich) Iteratoren anstelle von rohen Zeigern übergeben, da dies ausdrucksstärker ist. Das Übergeben von Iteratoren erstellt keine Kopie des Vektors.

2
John Dibling

Mein vector<int> foo enthält beispielsweise (5,2,6,87,251). Eine Funktion nimmt vector<int>* und ich möchte einen Zeiger auf (2,6,87,251) übergeben.

Ein Zeiger auf einen vector<int> ist überhaupt nicht dasselbe wie ein Zeiger auf die Elemente des Vektors.

Dazu müssen Sie einen neuen vector<int> erstellen, der nur die Elemente enthält, an die ein Zeiger übergeben werden soll. So etwas wie:

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

 // now you can pass &tempVector to your function

Wenn Ihre Funktion jedoch einen Zeiger auf ein array von int nimmt, können Sie &foo[1] übergeben.

1
Michael Burr

Verwenden Sie vector::front , es sollte die tragbarste Lösung sein. Ich habe dies verwendet, wenn ich mit einer festen API verbunden bin, die einen Zeichensatz möchte. Beispiel:

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

Eine sichere Version, um einen Iterator in einen Zeiger umzuwandeln (was genau das bedeutet, unabhängig von den Implikationen) und mit Sicherheit meine ich keine Sorge, den Iterator dereferenzieren zu müssen und mögliche Ausnahmen/Fehler aufgrund von end()/anderen Situationen zu verursachen

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

wird so etwas drucken

es = 0x0

es = 0x2202E10

Es ist eine unglaublich harte Art, es zu tun, aber wenn Sie es brauchen, erledigt es die Arbeit. Sie erhalten einige Compiler-Warnungen, die Sie mit #pragma entfernen können, wenn Sie wirklich gestört werden.

0
Shocker

Ich habe das nicht getestet, aber könnten Sie stattdessen ein Paar Iteratorenpaare verwenden? Jedes Iteratorpaar würde den Start- und End-Iterator des Sequenzvektors darstellen. Z.B.:

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

Offensichtlich müssen die Vektoren an anderer Stelle wie zuvor aufbewahrt werden. Wenn ein Sequenzvektor geändert wird, müsste sein Eintrag in der Gruppe entfernt und erneut hinzugefügt werden, da sich die Iteratoren möglicherweise geändert haben.

Jon

0
jon-hanson

Wenn Ihre Funktion wirklich vector<int> * (einen Zeiger auf den Vektor) verwendet, sollten Sie &foo übergeben, da dies ein Zeiger auf den Vektor ist. Offensichtlich löst das Ihr Problem nicht einfach, aber Sie können einen Iterator nicht direkt in einen Vektor konvertieren, da der Speicher an der Adresse des Iterators keinen gültigen Vektor direkt adressiert.

Sie können einen neuen Vektor konstruieren, indem Sie den Vektor-Konstruktor aufrufen:

template <class InputIterator> vector(InputIterator, InputIterator)

Dadurch wird ein neuer Vektor erstellt, indem die Elemente zwischen den beiden Iteratoren kopiert werden. Sie würden es ungefähr so ​​verwenden:

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

Vector ist eine Schablonenklasse, und es ist nicht sicher, den Inhalt einer Klasse in einen Zeiger zu konvertieren: Sie können die Vektorklasse nicht erben, um diese neue Funktionalität hinzuzufügen. _. Erstellen Sie einen weiteren Vektor von int Vector temp_foo (foo.begin [X], foo.end ()); Und übergeben Sie diesen Vektor an Ihre Funktionen

0
vivek sapru