Ich habe std::vector
Objekte einer bestimmten Klasse A
. Die Klasse ist nicht trivial und hat Kopierkonstruktoren und Verschiebungskonstruktoren definiert.
std::vector<A> myvec;
Wenn ich den Vektor mit A
Objekten fülle (z. B. myvec.push_back(a)
), wird der Vektor größer und verwendet den Kopierkonstruktor A( const A&)
, um neue Kopien der Elemente im Vektor zu instanziieren.
Kann ich irgendwie durchsetzen, dass der Verschiebungskonstruktor der Klasse A
stattdessen verwendet wird?
Antworten:
Sie müssen C ++ (speziell
std::vector
) darüber informieren, dass Ihr Verschiebungskonstruktor und Destruktor nicht werfennoexcept
. Dann wird der Verschiebungskonstruktor aufgerufen, wenn der Vektor wächst.So deklarieren und implementieren Sie einen Verschiebungskonstruktor, der beachtet wird von
std::vector
:Wenn dies nicht der Fall ist
noexcept
,std::vector
kann der Konstruktor ihn nicht verwenden, da er die vom Standard geforderten Ausnahmegarantien nicht gewährleisten kann.Weitere Informationen zu den im Standard enthaltenen Informationen finden Sie unter C ++ Move-Semantik und Ausnahmen
Dank an Bo, der angedeutet hat, dass dies möglicherweise mit Ausnahmen zu tun hat. Beachten Sie auch den Rat und die Verwendung von Kerrek SB,
emplace_back
wenn dies möglich ist. Es kann schneller sein (ist es aber oft nicht), es kann klarer und kompakter sein, aber es gibt auch einige Fallstricke (insbesondere bei nicht expliziten Konstruktoren).Bearbeiten , oft ist die Standardeinstellung das, was Sie wollen: Verschieben Sie alles, was verschoben werden kann, kopieren Sie den Rest. Um explizit danach zu fragen, schreiben Sie
Wenn Sie dies tun, erhalten Sie nach Möglichkeit noexcept: Ist der Standardkonstruktor Move als noexcept definiert?
Beachten Sie, dass frühere Versionen von Visual Studio 2015 und älter dies nicht unterstützten, obwohl es die Verschiebungssemantik unterstützt.
quelle
value_type
‚s move Ctor istnoexcept
? Vielleicht schränkt die Sprache den Funktionsaufrufkandidaten ein, wenn der aufrufende Bereich auch einenoexcept
Funktion ist?noexcept
Verschiebungskonstruktor gibt.is_nothrow_move_constructible
wird wahr sein, wenn es einennothrow
Kopierkonstruktor gibt. Mir ist kein wirklicher Fall von teurennothrow
Kopierkonstruktoren bekannt, daher ist nicht klar, dass es wirklich wichtig ist.noexcept
sowohl im Header als auch in der Implementierung markiert. Wenn ich einen push_back (std :; move) ausführe, wird der Kopierkonstruktor weiterhin aufgerufen. Ich reiße mir hier draußen die Haare.std::move()
beim falschenpush_back()
Anruf verwendet. Eine dieser Situationen, in denen Sie so intensiv nach einem Problem suchen, dass Sie den offensichtlichen Fehler nicht direkt vor sich sehen. Und dann war es Mittag und ich habe vergessen, meinen Kommentar zu löschen.Interessanterweise verwendet der Vektor von gcc 4.7.2 nur den Verschiebungskonstruktor, wenn sowohl der Verschiebungskonstruktor als auch der Destruktor vorhanden sind
noexcept
. Ein einfaches Beispiel:Dies gibt das erwartete aus:
Allerdings, wenn ich entferne
noexcept
aus~foo()
, das Ergebnis ist anders:Ich denke, das beantwortet auch diese Frage .
quelle
Es scheint, dass die einzige Möglichkeit (für C ++ 17 und früher), die
std::vector
Verwendung der Verschiebungssemantik bei der Neuzuweisung zu erzwingen , darin besteht, den Kopierkonstruktor zu löschen :). Auf diese Weise werden Ihre Kompilierungskonstruktoren verwendet oder beim Kompilieren versucht :).Es gibt viele Regeln, bei denen der
std::vector
Verschiebungskonstruktor bei der Neuzuweisung NICHT verwendet werden darf, aber nichts darüber, wo er verwendet werden darf .Leben
oder
Live-Code
Ihre
T
Klasse muss über einennoexcept
Verschiebungskonstruktor / Zuweisungsoperator und einennoexcept
Destruktor verfügen . Andernfalls wird ein Kompilierungsfehler angezeigt.quelle