Nach vielen Untersuchungen mit valgrind bin ich zu dem Schluss gekommen, dass std :: vector eine Kopie eines Objekts erstellt, das Sie push_back möchten.
Stimmt das wirklich ? Ein Vektor kann ohne Referenz keine Referenz oder einen Zeiger eines Objekts behalten ?!
Vielen Dank
*
oder ändern&
, um einen Zeiger oder eine Referenz zu erstellen.push_back
: es braucht aconst&
. Entweder wird der Wert weggeworfen (nutzlos), oder es gibt eine Abrufmethode. Wir sehen uns also die Signatur vonback
an und sie wird einfach zurückgegeben&
, sodass entweder der ursprüngliche Wert kopiert oder der Wertconst
stillschweigend weggeworfen wurde (sehr schlecht: möglicherweise undefiniertes Verhalten). Unter der Annahme, dass die Designer vonvector
rational waren (vector<bool>
nicht widerstehen), schließen wir, dass es Kopien macht.Antworten:
Ja,
std::vector<T>::push_back()
erstellt eine Kopie des Arguments und speichert es im Vektor. Wenn Sie Zeiger auf Objekte in Ihrem Vektor speichern möchten, erstellen Sie einestd::vector<whatever*>
anstelle vonstd::vector<whatever>
.Sie müssen jedoch sicherstellen, dass die Objekte, auf die die Zeiger verweisen, gültig bleiben, während der Vektor einen Verweis auf sie enthält (intelligente Zeiger, die die RAII-Sprache verwenden, lösen das Problem).
quelle
push_back
Führt seit C ++ 11 eine Verschiebung anstelle einer Kopie durch, wenn das Argument eine rWert-Referenz ist. (Objekte können mit in. Wertreferenzen mit konvertiert werdenstd::move()
.)emplace_back
, um jegliches Kopieren oder Verschieben zu vermeiden (Objekt an Ort und Stelle konstruieren, das vom Container bereitgestellt wird).Ja,
std::vector
speichert Kopien. Woher sollten Sievector
die erwarteten Lebensdauern Ihrer Objekte wissen?Wenn Sie das Eigentum an den Objekten übertragen oder teilen möchten, verwenden Sie Zeiger, möglicherweise intelligente Zeiger wie
shared_ptr
(in Boost oder TR1 ), um die Ressourcenverwaltung zu vereinfachen.quelle
boost::ptr_vector
?class Foo { typedef boost::shared_ptr<Foo> ptr; };
es auch gerne, um nur zu schreibenFoo::ptr
.shared_ptr
ist nicht gerade Feuer und vergessen. Siehe stackoverflow.com/questions/327573 und stackoverflow.com/questions/701456Von C ++ 11 ab, alle Standardcontainer (
std::vector
,std::map
usw.) convoy Semantik, was bedeutet , dass Sie jetzt rvalues zu Standardcontainer und vermeiden eine Kopie passieren kann:Alternativ können Sie verschiedene intelligente Zeiger verwenden, um größtenteils den gleichen Effekt zu erzielen:
std::unique_ptr
Beispielstd::shared_ptr
Beispielquelle
std::make_unique
(ärgerlicherweise) nur in C ++ 14 und höher verfügbar ist. Stellen Sie sicher, dass Sie Ihren Compiler anweisen, seine Standardkonformität entsprechend festzulegen, wenn Sie diese Beispiele kompilieren möchten.auto pFoo =
Wiederholungen vermeiden. und allestd::string
Casts können entfernt werden (es gibt eine implizite Konvertierung von String-Literalen instd::string
)make_unique
kann leicht in C ++ 11 implementiert werden, so ist es nur ein kleiner Ärger für jemanden, der mit einem C ++ 11-Compiler feststeckttemplate<typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>{new T{args...}}; }
std::move()
mit verwendenstd::shared_ptr
, wird der Zeiger des gemeinsam genutzten ursprünglichen Zeigers möglicherweise geändert, seit der Besitz an den Vektor übergeben wurde. Siehe hier: coliru.stacked-crooked.com/a/99d4f04f05e5c7f3std :: vector erstellt immer eine Kopie von allem, was im Vektor gespeichert ist.
Wenn Sie einen Zeigervektor beibehalten, wird eine Kopie des Zeigers erstellt, nicht jedoch die Instanz, auf die der Zeiger zeigt. Wenn Sie mit großen Objekten arbeiten, können (und sollten) Sie immer einen Zeigervektor verwenden. Die Verwendung eines Vektors von intelligenten Zeigern eines geeigneten Typs ist häufig aus Sicherheitsgründen gut, da die Handhabung der Objektlebensdauer und der Speicherverwaltung ansonsten schwierig sein kann.
quelle
Std :: vector erstellt nicht nur eine Kopie von allem, was Sie zurückschieben, sondern die Definition der Auflistung besagt auch, dass dies der Fall ist und dass Sie möglicherweise keine Objekte ohne die korrekte Kopiersemantik innerhalb eines Vektors verwenden. So verwenden Sie beispielsweise nicht auto_ptr in einem Vektor.
quelle
Relevant in C ++ 11 ist die
emplace
Familie der Elementfunktionen, mit denen Sie das Eigentum an Objekten übertragen können, indem Sie sie in Container verschieben.Die Gebrauchssprache würde so aussehen
Die Verschiebung für das lvalue-Objekt ist wichtig, da es sonst als Referenz oder const-Referenz weitergeleitet würde und der Verschiebungskonstruktor nicht aufgerufen würde.
quelle
wenn Sie nicht die Kopien wollen; Dann ist es am besten, einen Zeigervektor (oder eine andere Struktur, die für dasselbe Ziel dient) zu verwenden. wenn Sie die Kopien wollen; benutze direkt push_back (). Sie haben keine andere Wahl.
quelle
Warum waren viele Valgrind-Untersuchungen erforderlich, um dies herauszufinden? Beweisen Sie es sich einfach mit einem einfachen Code, z
Wenn "Hallo Welt" gedruckt wird, muss das Objekt kopiert worden sein
quelle