Wie kann man einen Iterator um 2 erhöhen?

72

Kann mir jemand sagen, wie man den Iterator um 2 erhöht?

iter++ist verfügbar - muss ich tun iter+2? Wie kann ich das erreichen?

Süß
quelle
4
Nach dem Umfang der Antworten zu urteilen, müssen Sie möglicherweise Ihre Frage klären.
Teabot
Ja. Was ist das für ein Iterator? Code anzeigen.
Brian Neal

Antworten:

106

std::advance( iter, 2 );

Diese Methode funktioniert für Iteratoren, die keine Iteratoren mit wahlfreiem Zugriff sind, kann jedoch durch die Implementierung so spezialisiert werden, dass sie nicht weniger effizient ist als iter += 2bei Verwendung mit Iteratoren mit wahlfreiem Zugriff.

CB Bailey
quelle
1
Was passiert, wenn der Iterator derzeit auf das letzte Element zeigt? Wo wird es nach dem Inkrement zeigen? Ich habe es mit VC ++ versucht - es wird nur weiterentwickelt und der Vergleich mit vector :: end () gibt danach false zurück. Dies ist vermutlich ein direkter Weg zu undefiniertem Verhalten.
Scharfzahn
1
Ja, wenn Sie std :: advanced mit '2' oder + = 2 oder zwei '++' ausführen möchten, ohne in der Mitte nach 'end' zu suchen, benötigen Sie eine externe Garantie, dass dies nicht der Fall ist Ich werde über das Ende hinausgehen. (Zum Beispiel könnten Sie wissen, dass Sie durch die geradzahligen (nullbasierten) Elemente einer Sammlung iterieren, die garantiert eine gerade Anzahl von Elementen enthält.)
CB Bailey
Was ist der Unterschied zwischen next (iter, 2) und next (iter, 2)
m1350
30

http://www.cplusplus.com/reference/std/iterator/advance/

std::advance(it,n);

Dabei ist n in Ihrem Fall 2.

Das Schöne an dieser Funktion ist, dass wenn "es" ein Iterator mit wahlfreiem Zugriff ist, das schnelle

it += n

Operation wird verwendet (dh Vektor <,,> :: Iterator). Ansonsten wird es gerendert

for(int i = 0; i < n; i++)
    ++it;

(dh Liste <..> :: Iterator)

Maik Beckmann
quelle
22

Wenn Sie keinen veränderbaren Wert eines Iterators haben oder eine Kopie eines bestimmten Iterators erhalten möchten (wobei der ursprüngliche unverändert bleibt), verfügt C ++ 11 über neue Hilfsfunktionen - std::next/ std::prev:

std::next(iter, 2);          // returns a copy of iter incremented by 2
std::next(std::begin(v), 2); // returns a copy of begin(v) incremented by 2
std::prev(iter, 2);          // returns a copy of iter decremented by 2
Piotr Skotnicki
quelle
Wenn ich einen Iterator wie diesen habe: map<string,string>::iterator iter; for(iter = variations.begin(); iter != variations.end(); iter++) { map<string,string>::iterator it_tmp = std::next(iter, 1); // increment by 1 it_tmp = std::next(iter, 2); // increment by 2 }Wird der Iter um 2 erhöht? oder iter wird nur it_tmp beeinflussen?
Hani Goc
@ HaniGoc Nur it_tmp
Metamorphose
8

Sie können den Operator 'Zuweisung durch Addition' verwenden

iter += 2;
Teabot
quelle
Ich habe mich gefragt, ob ++ iter ++ funktionieren würde, aber ich denke, das wäre nur verwirrend.
Xetius
2
Was passiert, wenn der Iterator derzeit auf das letzte Element zeigt? Wo wird es nach dem Inkrement zeigen?
Scharfzahn
4
@ Xetius: Du solltest es nicht tun. Es ist undefiniertes Verhalten.
Naveen
2
++ iter ++ bindet als ++ (iter ++), iter ++ ist kein modifizierbarer Wert, daher können Sie ++ (iter ++) nicht 'tun'. Wenn es erlaubt wäre, würde es wahrscheinlich nicht das tun, was von ihm erwartet werden könnte.
CB Bailey
3
Dies funktioniert nicht für alle Iteratortypen. Nur RandomAccessIterators sind erforderlich, um das Hinzufügen zu unterstützen.
Steve Jessop
5

Wenn Sie nicht wissen, ob Sie genügend nächste Elemente in Ihrem Container haben oder nicht, müssen Sie zwischen jedem Inkrement das Ende Ihres Containers überprüfen. Weder ++ noch std :: advanced werden dies für Sie tun.

if( ++iter == collection.end())
  ... // stop

if( ++iter == collection.end())
  ... // stop

Sie können sogar Ihre eigene gebundene sichere Vorausfunktion ausführen.

Wenn Sie sicher sind, dass Sie das Ende nicht überschreiten, ist std :: advanced (iter, 2) die beste Lösung.

Jem
quelle
5

Wir können sowohl std :: advanced als auch std :: next verwenden , aber es gibt einen Unterschied zwischen den beiden.

advanceändert sein Argument und gibt nichts zurück. So kann es verwendet werden als:

vector<int> v;
v.push_back(1);
v.push_back(2);
auto itr = v.begin();
advance(itr, 1);          //modifies the itr
cout << *itr<<endl        //prints 2

next gibt eine geänderte Kopie des Iterators zurück:

vector<int> v;
v.push_back(1);
v.push_back(2);
cout << *next(v.begin(), 1) << endl;    //prints 2
skpro19
quelle
0

Angenommen, die Listengröße ist möglicherweise nicht ein Vielfaches der Schritte, die Sie gegen Überlauf schützen müssen:

static constexpr auto step = 2;

// Guard against invalid initial iterator.
if (!list.empty())
{
    for (auto it = list.begin(); /*nothing here*/; std::advance(it, step))
    {
        // do stuff...

        // Guard against advance past end of iterator.
        if (std::distance(it, list.end()) > step)
            break;
    }
}

Abhängig von der Implementierung der Sammlung kann die Entfernungsberechnung sehr langsam sein. Unten ist optimal und besser lesbar. Der Abschluss kann in eine Dienstprogrammvorlage geändert werden, deren Listenendwert als const-Referenz übergeben wird:

const auto advance = [&](list_type::iterator& it, size_t step)
{
    for (size_t i = 0; it != list.end() && i < step; std::next(it), ++i);
};

static constexpr auto step = 2;

for (auto it = list.begin(); it != list.end(); advance(it, step))
{
    // do stuff...
}

Wenn es keine Schleife gibt:

static constexpr auto step = 2;
auto it = list.begin();

if (step <= list.size())
{
    std::advance(it, step);
}
evoskuil
quelle
Was ist die zeitliche Komplexität von "std :: advanced (it, step);".
Sanjit Prasad
-7

Die sehr einfache Antwort:

++++iter

Die lange Antwort:

Eigentlich sollte man gewöhnen Schreiben ++iterstattiter++ . Letzterer muss den alten Wert zurückgeben (eine Kopie davon), der sich vom neuen Wert unterscheidet. Das braucht Zeit und Raum.

Beachten Sie, dass das Präfix increment ( ++iter) einen l-Wert annimmt und einen l-Wert zurückgibt, während das postfix-Inkrement ( iter++) einen l-Wert annimmt und einen r-Wert zurückgibt.

Jonas Kölker
quelle
5
Undefiniertes Verhalten, wenn iteres sich um einen Rohzeiger handelt (was einige Iteratortypen sein können). ++it; ++it;wäre in Ordnung.
Steve Jessop
1
Bitte sagen Sie mir, dass dies keine ernsthafte Antwort ist.
Achse