warum ist der Destruktor-Aufruf nach dem std::move erforderlich?
In Der Programmiersprache C++ Edition 4 es ist ein Beispiel für ein Vektor-Implementierung, siehe entsprechende code am Ende der Nachricht.
uninitialized_move() initialisiert neuen T-Objekte in neuen Speicherbereich, indem Sie Sie aus den alten Speicherbereich. Dann ruft er den Destruktor auf den original T-Objekt, das verschoben-vom Objekt. Warum ist der Destruktor-Aufruf in diesem Fall notwendig?
Hier ist meine unvollständige Verständnis: die Verschiebung eines Objektes bedeutet, dass das Eigentum an den Ressourcen, die im Besitz der bewegt-vom Objekt übertragen werden, um die bewegt-zu-Objekt. Die Reste in die bewegt-vom Objekt sind einige mögliche Mitglieder von built-in Typen, die müssen nicht zerstört werden, Sie wird freigegeben, wenn der die vector_base b geht out of scope (innen reserve(), nach der swap() nennen). Alle Zeiger in die bewegt-vom Objekt gesetzt werden, um nullptr oder einen Mechanismus beschäftigt ist, fallen das Eigentum von bewegt-von der Objekt-auf diese Ressourcen, so dass wir sicher sind, warum dann rufen Sie den Destruktor auf eine aufgebraucht-Objekt, wenn die "vector_base b" Destruktor wird sowieso freigeben von Speicher nach der swap gemacht wird?
Verstehe ich die Notwendigkeit der explizite Aufruf des destruktors in den Fällen, wenn es aufgerufen werden muss, denn wir haben etwas zu zerstören (z.B. drop-Elemente), aber ich kann nicht erkennen, seine Bedeutung nach der std::move + Freigabe von vector_base. Ich Lesen Sie einige Texte über das Netz und ich sehe den Destruktor aufrufen, die bewegt-vom Objekt als ein signal (zu wem oder was?) dass die Lebensdauer des Objekts ist vorbei.
Bitte erläutern Sie mir, was eine sinnvolle Arbeit zu tun bleibt, um von den Destruktor? Danke!
Das code-snippet unten ist von hier aus http://www.stroustrup.com/4th_printing3.html
template<typename T, typename A>
void vector<T,A>::reserve(size_type newalloc)
{
if (newalloc<=capacity()) return; //never decrease allocation
vector_base<T,A> b {vb.alloc,size(),newalloc-size()}; //get new space
uninitialized_move(vb.elem,vb.elem+size(),b.elem); //move elements
swap(vb,b); //install new base
} //implicitly release old space
template<typename In, typename Out>
Out uninitialized_move(In b, In e, Out oo)
{
using T = Value_type<Out>; //assume suitably defined type function (_tour4.iteratortraits_, _meta.type.traits_)
for (; b!=e; ++b,++oo) {
new(static_cast<void*>(&*oo)) T{move(*b)}; //move construct
b->~T(); //destroy
}
return oo;
}
- Dies ist eine generische Implementierung, die Sie nicht selbst jetzt, wenn
T{move(*b)}
fordert eine move-Konstruktor. - Glaube nicht, dass über den Umzug zu viel. Zur ersten Annäherung, Bewegung ist genauso wie das kopieren, und die Welt immer noch nach den gleichen Regeln spielt.
- 🙂 aber Bewegung ist sehr wichtig, gerade weil es nicht kopieren, das ist zu teuer, um in einigen Fällen, so habe ich, um darüber nachzudenken, wie anders kopieren. Mit der Kopie kann ich entscheiden, legen Sie die original oder nicht, mit bewegen ich sagen "ich bin jetzt der neue Eigentümer von Ihr Eigentum und Sie sind erschöpft"
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bewegen von einem Objekt bedeutet nur, dass, die bewegt-von der Objekt könnte Spenden Ihr Mut zu Leben, in einem anderen live-Objekt kurz vor es ist [wahrscheinlich] sterben. Beachten Sie jedoch, dass, nur weil ein Objekt gespendet, die Eingeweide, dass das Objekt nicht tot ist! In der Tat, es kann wiederbelebt werden, indem eine weitere Spende von Objekt und live auf das Objekt Eingeweide.
Außerdem ist es wichtig zu verstehen, dass verschieben der Konstruktion oder verschieben Sie die Zuordnung von tatsächlich kopiert! In der Tat, Sie wird werden kopiert, wenn der Typ bewegt wird passiert zu sein, ein pre-C++11-Typ mit einem copy-Konstruktor oder eine Kopie der Abtretung. Auch wenn eine Klasse einen move-Konstruktor, oder ein move-Zuweisung es kann vorkommen, dass es sich nicht mehr bewegen können seinen Mut, um das neue Objekt, z.B., weil die allocators überein.
In jedem Fall eine bewegte Objekt kann noch Ressourcen haben, oder benötigen Statistiken oder was auch immer. Um loszuwerden, das Objekt muss zerstört werden. Abhängig von der Klasse der Verträge kann es auch einen definierten Zustand, nachdem er zog aus und konnte mit neuer verwenden, ohne weitere Umschweife.
vector<T>
kann jedes Mitglied aufgerufen ist, die keine Voraussetzung. Dies beinhaltetempty()
,clear()
undsize()
.std::ifstream
zum Beispiel). Wenn RAII (fürstd::ifstream
, es gibt einen Weg, um ihn zu initialisieren, ohne den Erwerb einer Ressource), es gibt keine möglichen gültigen Zustand, wenn die Ressource verschoben wurde. Mit einer leeren Zustand, die bewegt-vom Objekt können noch einen gültigen Status haben; vielleicht ist meine "Regel" war daher zu übertrieben und hätte "das absolute minimum Sie sich verlassen können". Hast du einen link wo dies genauer beschrieben?std::enable_if
oderstatic_assert
oder ähnlich), dass die value_type iststd::is_nothrow_move_constructible
, dannstd::move
nicht wirklich verlassen, nichts Wert zu zerstören, die hinter, und es sollte sicher sein das weglassen der Platzierung Destruktoren. Ist diese Argumentation korrekt?std::swap
Algorithmus mit deiner Frage in den Sinn. Das ist nicht zu sagen, die "destruktive move-Semantik" würde nicht sinnvoll sein. Ich bin sicher, es würde. Aber wenn ich die Wahl hätte zwischen einer "konstruktiven move-Semantik" und "zerstörerischen move-Semantik", ich würde ersteres wählen, und genau das war die Wahl, wir mussten vor einem Jahrzehnt. Siehe open-std.org/jtc1/sc22/wg21/docs/papers/2002/... für ein paar mehr details über diese Wahl.