Ist es sicher, push_back ein element aus der selben Vektor?
vector<int> v;
v.push_back(1);
v.push_back(v[0]);
Wenn die zweite push_back bewirkt eine Umverteilung der Verweis auf die erste Ganzzahl in der Vektor wird nicht mehr gültig sein. Also, das ist nicht sicher?
vector<int> v;
v.push_back(1);
v.reserve(v.size() + 1);
v.push_back(v[0]);
Ist es sicher?
- Da ist ein Fehler in Visual Studio 2010: stackoverflow.com/questions/10218223/...
- Ein Hinweis: Es gibt derzeit eine Diskussion in der standard-Vorschläge-forum. Als Teil davon, hat jemand eine Beispiel-Implementierung
push_back
. Ein weiteres Plakat bemerkt einen Fehler, dass es nicht ordnungsgemäß behandelt den Fall, den Sie beschreiben. Niemand sonst, soweit ich das beurteilen kann, argumentiert, dass dies nicht ein bug. Nicht sagen, dass schlüssigen Beweis, nur eine Beobachtung. - Tut mir Leid, aber ich weiß nicht, die Antwort zu akzeptieren, denn es gibt immer noch Streit über die richtige Antwort.
- Ich denke, dass der "bug" war eine Frage der Robustheit arbeiten mit real-world-code, und nicht die Konformität.
- Ähnlicher Fall: stackoverflow.com/questions/11511510/...
- Ich wurde gebeten, zu kommentieren, auf diese Frage durch die 5. Kommentar unter: stackoverflow.com/a/18647445/576911. Ich bin dabei und upvoting jede Antwort, die derzeit sagt: ja, es ist sicher zu push_back ein element aus dem gleichen Vektor.
- Werden Sie dann sagen, dass jeder
Requires:
Bedingung und Voraussetzung in der gesamten Norm gilt nur, wenn die Funktion aufgerufen wird, und Sie zu brechen, bevor die Funktion zurückkehrt, ist erlaubt, es sei denn er läuft in Konflikt mit irgendeiner anderen Regel? Denn das ist die einzige Möglichkeit, die Standard interpretiert wurde dies zulassen. - Ich sage, dass wenn dies nicht erlaubt, es müsste eine Erfordert verbieten es. Zum Beispiel siehe Tabelle 100 - Sequence-Anforderungen für container,
a.insert(p,i,j)
, pre: i und j sind nicht Iteratoren in einem. Siehe auch [res.auf.Argumente]/p1/b3, der effektiv sagt, dass, wenn Sie tunv.push_back(move(v[0]));
dann ist es nicht garantiert, um zu arbeiten. Wenn Sie etwas bewegen, die std::lib ist zulässig, zu vermuten, was Sie bewegt, ist wirklich ein prvalue. Aber ich kenne keine Einschränkungen in Bezug aufv.push_back(v[0]);
. Zusätzlich ich bin mir bewusst, dass alle std::lib implementors hart arbeiten, um diese Arbeit zu machen. - Sie sagen also, dass, obwohl der Standard verlangt die übergabe eines gültigen Verweis auf
push_back
, es ist ok, um pass ein, dass Sie wissen, unterliegt der drohenden Abwertung? Mit dieser begrenzten Sicht auf die FunktionenRequires
aka Voraussetzungen, ich könnte brechen die meisten, wenn nicht alle algorithmen beschrieben in der Norm. - Wenn Sie nicht einverstanden sind mit dem, was der standard sagt, oder auch wenn Sie einverstanden mit dem standard, aber glaube nicht, dass er sagt es deutlich genug, das ist immer eine option für Sie: cplusplus.github.io/LWG/lwg-aktiv.html#submit_issue habe ich diese Möglichkeit, mich öfter als ich mich erinnern kann. Manchmal erfolgreich, manchmal nicht. Wenn Sie möchten, zu diskutieren, was der standard sagt, oder was er sagen sollte, ALSO nicht ein wirksames forum. Unser Gespräch hat keine normative Bedeutung. Sie können aber eine chance haben, in eine normative Wirkung, indem Sie den link oben.
- Sind Sie sicher, dass Sie konnte? Es gibt durchaus ein paar Regeln in der Algorithmen-Bibliothek über das, was Ihre Funktionen sind erlaubt, das zu tun.
- ja, ziemlich sicher. Ich werde arbeiten müssen, bis es ein Beispiel nach der Arbeit und sehen, ob Sie können den Namen für jede Regel, die er verletzt.
Requires:
ist eine Voraussetzung, nicht eine invariante.- Es gibt zwei verschiedene Definitionen für das Wort Invarianten auch. Eines ist eine Tatsache, ist immer wahr, wenn eine bestimmte Codezeile erreicht ist. Voraussetzung sicher qualifiziert, da diese Art von invariante. Ein weiterer ist die Tatsache, dass hält vom Ende der Konstruktor bis zum Beginn der Zerstörung, möglicherweise mit Ausnahmen, während ein lock gehalten wird. Diese zweite definition nicht wirklich zu Funktion Argumente (andere als Konstruktor-Argumente, die gespeichert werden für die Lebensdauer des Objekts an, zum Beispiel mit Mitglieder-Daten der Referenz-Typ).
- Eine Voraussetzung gelten nicht als invariante. Eine invariante auf der anderen Seite ist auch eine Voraussetzung. Dass gesagt wird, eine invariante kann für jedes sub-Programm, ob eine Klasse, ein Modul, Methode, Funktion, Schleife oder einfache code-block. In Bezug auf die C++ - Spezifikationen, ich glaube
Requires:
bedeutet pre-Zustand, und nicht unveränderlich. Die Voraussetzung muss nur zu halten, die unmittelbar vor der Ausführung des sub-Programms. - Ist ein "loop-invariant" eine invariante? Ja, Voraussetzung ist eine invariante -- für mindestens einen trivialen (leeren) basic-block an den Anfang der Funktion.
- Könnte mir jemand erklären, warum das erste Beispiel in der Frage wäre unsicher? Ich bin ein bisschen ein Neuling, und ich habe Probleme, warum es vielleicht sein könnte ist unsicher. Danke!
- Wenn push_back bewirkt, dass der Vektor zu erreichen, die Kapazität, der Vektor Zuweisung einer neuen größeren Puffer, kopiere die alten Daten, und löschen Sie dann die alten Puffer. Dann wird es fügen das neue element ein. Das problem ist, das neue element ist ein Verweis auf Daten in der alten-Puffer, die gerade gelöscht wurde. Es sei denn, push_back macht eine Kopie des Werts, der vor dem löschen, es wird dann eine schlechte Referenz.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sieht es aus wie http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#526 adressiert dieses problem (oder etwas sehr ähnliches) als potentieller defekt in der standard:
Die vorgeschlagene Lösung war, dass es nicht ein Mangel:
v.insert(v.begin(), v[2]);
nicht der Auslöser einer Umverteilung. Also, wie macht dies die Frage beantworten?Ja, es ist sicher, und die standard-Bibliothek Implementierungen durch Reifen springen, um es so zu machen.
Ich glaube der Entwickler-trace-diese Forderung zurück auf 23,2/11 irgendwie, aber ich kann nicht herausfinden, wie, und ich kann nicht finden, etwas mehr Beton ist entweder. Die beste, die ich finden kann, ist dieser Artikel:
http://www.drdobbs.com/cpp/copying-container-elements-from-the-c-li/240155771
Inspektion von libc++und libstdc++'s Implementierungen zeigt, dass Sie auch sicher.
vec.insert(vec.end(), vec.begin(), vec.end());
?vec.end()
ist wie ein iterator.vector.push_back
NICHT anderweitig angeben. "Ursachen Umverteilung, wenn die neue Größe größer ist als die alte Kapazität." und (beireserve
) "Neuzuweisung ungültig werden alle Referenzen, Pointer und Iteratoren unter Bezugnahme auf die Elemente in der Sequenz."Die Norm garantiert auch Ihr erstes Beispiel, um sicher zu sein. Zitieren C++11
[sequence.Bestand]
So, obwohl es nicht gerade trivial, die Implementierung muss garantieren, es wird nicht zum erlöschen der Referenz, wenn dabei die
push_back
.push_back
verhält sich so, als wenn das argument wird als Wert übergeben. Ich bin mir nicht sicher, obwohl.t
". Wie kann man diese entkräftent
? In der Zeit, die Sie übergeben Sie die Referenz gültig ist.t
, die Frage ist nur, ob vor oder nach der Anfertigung der Kopie. Dein letzter Satz ist sicher falsch.t
entspricht den aufgeführten Voraussetzungen, die das beschriebene Verhalten ist garantiert. Eine Implementierung ist nicht zulässig, ungültig, vorausgesetzt, und dann verwenden, die als Entschuldigung, sich nicht zu Verhalten, wie angegeben.std::for_each
ist erforderlich, um zu arbeiten, auch wenn der Funktor wird, erlischt die end-iterator für den Bereich? Wie wäre es mal entdecken Sie die neue gültige Ende-iterator? Sie müssen sicherstellen, dass die Voraussetzungen erfüllt sind, in der gesamten Anruf.for_each
erforderlich ist, nicht zur Unwirksamkeit der Iteratoren. Ich kann nicht kommen mit einer Referenz fürfor_each
, aber ich sehe auf einige algorithmen, die text wie "op und binary_op begründet nicht die Unwirksamkeit Iteratoren oder Teilbereiche".accumulate
undinner_product
,partial_sum
, undadjacent_difference
.std::for_each()
ist erlaubt das ändern der Reihenfolge der Elemente.for_each
gültig (für die Dauer des Gesprächs). (Gut, einige Container erlauben würde einige strukturelle Veränderungen vorgenommen und noch garantieren, dass Iteratoren und Referenzen bleiben gültig)commit()
bei19:11
. Er hat geschriebenx.push_back(x.back());
. Jetzt sehe ich, es ist jemand, der interpretiert den text wie ich es Tat.Requires:
Dokumentation ist eine Voraussetzung, aber es ist nicht nur Voraussetzung. Es ist stärker. Oder halten Sie es für einen Fehler, die die Standard-vernachlässigt zu sagen, dass die copy-Konstruktoren müssen nicht ungültig Iteratoren und vernachlässigt zu sagen, dass move-Konstruktoren müssen nicht ungültig Iteratoren und vernachlässigt zu sagen, dass die Zuweisung Anrufe müssen nicht ungültig Iteratoren und das iterator-Inkrement-Funktionen müssen nicht Iteratoren ungültig werden. Das wird sehr chaotisch werden sehr schnell. Nein, dieRequires:
- Klauseln gelten für die gesamte Dauer des Gesprächs.operator()
. Aber ob das ein Mangel ist oder nicht, hat der Ausschuss war sich im klaren über die richtige interpretation der Anforderungen aufinsert
, die gewährleisten, dass diese gut definierten und tragbaren.binary_op
's kopieren/verschieben/was auch immer, ich meine, für den element-Typ. Wenn Sie Lesen, dierequires:
als "zum Zeitpunkt des Aufrufs nur", ich finde Schlupflöcher überall.push_back
undinsert
. Aber die Tatsache, dass die Anforderungen zu erwarten sind, um zu bleiben gültig für die Dauer des gesamten Anrufs ist ein sehr Allgemeines Prinzip. Und Nein, es gibt keinen Weg, um in der Regel geben Sie die Anforderung nicht entkräften, weil es speziell für die Parameter jedes Algorithmus.vector::push_back
undvector::insert
nicht haben "- Effekte: "- Klauseln und nicht angegeben, als 'Gleichwertig' einige code-Sequenz, so 17.5.1.4/4 nicht gelten.Requires:
und Voraussetzungen enthält die Dauer der Funktion für Klauseln, die den entsprechenden code, nicht aber für andere Klauseln?B(); C();
. x wird nicht zu einer Voraussetzung von(). Wenn das Voraussetzung nicht halten, dann ist es noch in Ordnung sein kann, call A() solange (B) stellt die Voraussetzung x für C().C()
undB()
hat keine Wirkung auf Sie, dann ist, wie beschrieben inA()
's Vertrag?Ist es nicht offensichtlich, dass im ersten Beispiel ist sicher, weil die einfachste Implementierung
push_back
wäre zunächst eine Neuverteilung des Vektors, falls benötigt, und kopieren Sie dann die Referenz.Aber zumindest scheint es sicher zu sein, die mit Visual Studio 2010. Die Umsetzung der
push_back
macht die Besondere Handhabung der Fall, wenn Sie drücken Sie zurück, ein vector-element.Der code ist wie folgt aufgebaut:
Dies ist nicht eine Garantie der standard, aber als ein weiterer Datenpunkt,
v.push_back(v[0])
ist sicher für LLVM libc zu benutzen++.libc++'s
std::vector::push_back
Anrufe__push_back_slow_path
bei Bedarf reservieren Speicher:__swap_out_circular_buffer
, in welchem Fall diese Umsetzung ist in der Tat sicher.__swap_out_circular_buffer
. (Ich habe einige Kommentare Hinzugefügt, um beachten Sie, dass.)Die erste version ist definitiv NICHT sicher:
aus Abschnitt 17.6.5.9
Beachten Sie, dass in diesem Abschnitt auf Daten, die Rassen, die normalerweise Leute denken, der in Verbindung mit dem Durchzug... aber die eigentliche definition umfasst "passiert vor" Beziehungen, und ich sehe keine Bestellung Beziehung zwischen mehreren Nebenwirkungen von
push_back
im Spiel, nämlich der Verweis invalidation scheint nicht definiert zu werden wie bestellt mit Respekt zu kopieren-der Bau des neuen tail-element.v[0]
ist kein iterator, ebensopush_back()
nicht nehmen, einen iterator. Also, von einer Sprache, die Anwalt Perspektive, dein argument ist ungültig. Sorry. Ich weiß, dass die meisten Iteratoren sind Zeiger und der Punkt der Aufhebung, einen iterator, ist so ziemlich das gleiche wie für die Verweise, aber der Teil, von dem standard, den Sie zitieren, ist irrelevant für die situation auf der hand.x.push_back(x[0])
ist SICHER.Es ist völlig sicher.
In Ihrem zweiten Beispiel haben Sie
ist nicht notwendig, da beim Vektor geht von seiner Größe, wird es bedeuten, dass der
reserve
.Vektor ist verantwortlich für dieses Zeug, nicht Sie.
Beide sind sicher, da push_back wird der Wert kopiert, nicht die Referenz. Wenn Sie die Speicherung von Zeigern, das ist immer noch sicher wie weit der Vektor betrifft, sondern nur wissen, dass man zwei Elemente der Vektor zeigt auf die gleichen Daten.
Implementierungen von push_back müssen daher sicherstellen, dass eine Kopie
v[0]
eingefügt wird. Von counter Beispiel, vorausgesetzt, eine Umsetzung würde eine Neuverteilung vor dem kopieren, es würde nicht gewiß, hängen Sie eine Kopie vonv[0]
und als solche gegen die Spezifikationen.push_back
wird, jedoch auch Größe des vectors aus und in eine naive Implementierung dieser wird ungültig machen die Referenz vor dem kopieren Auftritt. So, es sei denn, Sie kann dies durch ein Zitat aus dem standard, ich werde es prüfen falsch.push_back
kopieren Sie den Wert in den Vektor; aber (soweit ich sehen kann), dass etwas geschehen nachdem Umverteilung, an welchem Punkt der Referenz, die versuchen zu kopieren, ist nicht mehr gültig.push_back
erhält das argument Verweis.push_back
und argument.push_back
ist nicht erlaubt zu entkräften, Iteratoren und Referenzen auf alles, selbst nach der macht seine Kopie? Das ist eindeutig nicht eine angemessene interpretation.v[0]
, und nicht das Objekt(s) auf die er sich bezieht? Bist du jetzt eigentlich stretching mögliche Bedeutung vonCopyInsertable
.v[0]
ist per definition das Objekt, auf das es sich bezieht. In keiner Weise wird meine Aussage impliziert, dass die referencev[0]
unverändert.Vom 23.3.6.5/1:
Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.
Da wir das einfügen am Ende, keine Referenzen werden ungültig wenn der Vektor nicht verändert. Also, wenn der Vektor s
capacity() > size()
dann ist es garantiert zu arbeiten, sonst ist es garantiert nicht definiertes Verhalten.references
Teil der Offerte.push_back
).