Einen umgezogenen Container wiederverwenden?

Lesezeit: 5 Minuten

Einen umgezogenen Container wiederverwenden
Ronag

Wie kann ein umgezogener Container richtig wiederverwendet werden?

std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);

// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize

container.push_back(2);
assert(container.size() == 1 && container.front() == 2);

Nach dem, was ich im C++0x-Standardentwurf gelesen habe; ver3 scheint der richtige Weg zu sein, da ein Objekt nach move in a ist

“Sofern nicht anders angegeben, müssen solche ausgelagerten Objekte in einen gültigen, aber nicht spezifizierten Zustand versetzt werden.”

Ich habe noch nie einen Fall gefunden, in dem es “anders angegeben” ist.

Obwohl ich ver3 etwas umständlich finde und ver1 viel lieber gewesen wäre, kann vec3 zwar einige zusätzliche Optimierungen ermöglichen, aber andererseits leicht zu Fehlern führen.

Ist meine Vermutung richtig?

  • Du könntest einfach anrufen clearda es keine Vorbedingungen hat (und daher nicht auf den Zustand des Objekts angewiesen ist).

    – Nicol Bolas

    6. Februar 2012 um 23:26 Uhr

  • @Nicol: Nehmen wir an, es gab eine std::vector Implementierung, die einen Zeiger auf seine Größe gespeichert hat (scheint albern, aber legal). Wenn Sie sich von diesem Vektor wegbewegen, kann der Zeiger NULL bleiben, danach clear würde versagen. operator= könnte auch scheitern.

    – Ben Voigt

    6. Februar 2012 um 23:27 Uhr


  • @Ben: Ich denke, das würde den “gültigen” Teil von “gültig, aber nicht spezifiziert” verletzen.

    – Ildjarn

    6. Februar 2012 um 23:29 Uhr


  • @ildjarn: Ich dachte, es bedeutet nur, dass es sicher ist, den Destruktor auszuführen.

    – Ben Voigt

    6. Februar 2012 um 23:36 Uhr

  • Ich denke, die Frage ist, was ist “gültig”?

    – ronag

    6. Februar 2012 um 23:38 Uhr


Aus Abschnitt 17.3.26 der Spezifikation “gültiger, aber nicht spezifizierter Zustand”:

ein Objektzustand, der nicht angegeben ist, außer dass die Invarianten des Objekts erfüllt sind und Operationen an dem Objekt sich wie für seinen Typ angegeben verhalten [ Example: If an object x of type std::vector<int> is in a valid but unspecified state, x.empty() can be
called unconditionally, and x.front() can be called only if x.empty() returns false. —end example ]

Daher ist das Objekt aktiv. Sie können jeden Vorgang ausführen, der keine Vorbedingung erfordert (es sei denn, Sie überprüfen zuerst die Vorbedingung).

clearhat zum Beispiel keine Vorbedingungen. Und es wird das Objekt in einen bekannten Zustand zurückversetzen. Also einfach löschen und wie gewohnt verwenden.

  • Wo kann ich im Standard etwas über “Voraussetzungen” für zB std::vector-Methoden lesen?

    – ronag

    6. Februar 2012 um 23:35 Uhr

  • @ronag: §23.2 enthält Tabellen, in denen diese aufgelistet sind.

    – Grizzly

    6. Februar 2012 um 23:45 Uhr

  • Folgendes fand ich interessant, open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.htmlschreiben sie „Behälter können ‚leer als leer‘ sein“.

    – ronag

    6. Februar 2012 um 23:57 Uhr


  • @ronag : 1) Wenn der Container in einem gültigen Zustand ist, dann Aufruf clear ist gültig. 2) Während der Behälter war in einem nicht näher bezeichneten Zustand, anrufend clear versetzt den Container in einen bestimmten Zustand, weil er im Standard vorgeschriebene Nachbedingungen hat (§23.2.3 Tabelle 100). std::vector<T> hat eine Klasseninvariante, die push_back() ist immer gültig (solange T ist CopyInsertable).

    – Ildjarn

    7. Februar 2012 um 0:00 Uhr


  • @ronag: open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.html zitierte einen der Kommentare der nationalen Körperschaft zum Zitat „leer als leer“. Der Kommentar der nationalen Körperschaft war falsch. N3241 hat einen solchen Zustand nicht vorgeschlagen. Wenn eine Implementierung eines std::containers einen “leerer als leer”-Zustand hat, der sich aus einem move-from ergibt, dann muss dieser Zustand ein gültiger Zustand sein (dh Sie können mit diesem Objekt alles tun, was keine Vorbedingungen erfordert).

    – Howard Hinnant

    7. Februar 2012 um 3:56 Uhr

Einen umgezogenen Container wiederverwenden
Grizzly

Das Objekt befindet sich in a gültiger, aber undefinierter Zustand bedeutet im Grunde, dass der genaue Zustand des Objekts zwar nicht garantiert, aber gültig ist und daher garantiert funktionieren, dass Member-Funktionen (oder Nicht-Member-Funktionen) funktionieren, solange sie sich nicht darauf verlassen, dass das Objekt einen bestimmten Zustand hat.

Die clear() Die Member-Funktion hat keine Vorbedingungen für den Zustand des Objekts (außer natürlich, dass sie gültig ist) und kann daher für verschobene Objekte aufgerufen werden. Andererseits bspw front() hängt davon ab, dass der Container nicht leer ist, und kann daher nicht aufgerufen werden, da nicht garantiert wird, dass er nicht leer ist.

Daher sollten sowohl ver2 als auch ver3 in Ordnung sein.

  • Ein Vektor wird immer leer sein, aber das gilt nicht für den allgemeinen Fall (IE-Array)

    – Muhende Ente

    6. Februar 2012 um 23:35 Uhr


  • “Ein Vektor wird immer leer sein”, worauf stützt du das?

    – ronag

    6. Februar 2012 um 23:36 Uhr

  • @ronag: Ich meinte natürlich ver2 und ver3 (wie aus dem Text hervorgehen sollte, wurde dieser Tippfehler behoben

    – Grizzly

    6. Februar 2012 um 23:39 Uhr

  • Interessanterweise Voraussetzungen für front() sind nur für angegeben std::arrayund selbst dort nicht in der Tabelle.

    – Ben Voigt

    6. Februar 2012 um 23:49 Uhr

  • @Ben: §23.2.3 Tabelle 100 besagt, dass die Betriebssemantik von front() sind *a.begin()§23.2.1/6 sagt “Wenn der Behälter leer ist, dann begin() == end()“, und §24.2.1/5 sagt “Die Bibliothek geht niemals davon aus, dass Werte nach dem Ende dereferenzierbar sind.“. Folglich denke ich, die Voraussetzungen für front() kann abgeleitet werden, obwohl es sicherlich deutlicher gemacht werden könnte.

    – Ildjarn

    7. Februar 2012 um 0:10 Uhr


1646644813 157 Einen umgezogenen Container wiederverwenden
Ben Voigt

Ich glaube nicht, dass Sie irgendetwas mit einem verschobenen Objekt tun können (außer es zu zerstören).

Kannst du nicht verwenden swap stattdessen alle Vorteile des Umzugs nutzen, aber den Container in einem bekannten Zustand belassen?

  • +1. swap ist eine gute Idee, obwohl es nicht in allen Fällen funktionieren wird, zB wird die Verwendung von auto nicht funktionieren. Vielleicht wäre ein safe_move, der intern Swap verwendet, eine Idee?

    – ronag

    6. Februar 2012 um 23:27 Uhr


  • Es ist ein Live-Objekt, und Sie können alle Funktionen verwenden, die keine Vorbedingungen haben (abgesehen von Invarianten).

    – Muhende Ente

    6. Februar 2012 um 23:36 Uhr


  • Die primäre Vorlage für std::swap hat 2 Move-Zuweisungen, wobei die Ziele dieser Zuweisungen von Werten verschoben werden. Das zählt für mich als “etwas mit einem verschobenen Objekt tun”.

    – Caleth

    8. Oktober 2018 um 11:23 Uhr

964750cookie-checkEinen umgezogenen Container wiederverwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy