2017-10-08 6 views
1

Ich denke, ich verstehe, wie der Stapel funktioniert und was passiert, wenn eine Variable verschoben wird, aber ich kann keine Antwort auf diese Frage finden. Lassen Sie mich erklären:Was passiert mit dem Stapel, wenn eine Variable in einen äußeren Bereich verschoben wird?

Wenn ein neuer Bereich eingegeben/erstellt wird, wird eine bestimmte Menge an Speicher oben auf dem Stapel erworben. Der Stapelzeiger zeigt auf diesen Speicher. Es repräsentiert die aktuelle Größe des Stapels. Wenn der Bereich verlassen wird, wird der Speicher freigegeben, indem der Stapelzeiger an die vorherige Position zurückkehrt.

Verschieben Semantik in C++ 11 oder später verschieben Besitz von einigen Daten von einer Variablen zu einer anderen. Dies vermeidet das Kopieren von Daten, da der Speicher, der die Daten enthält, derselbe bleibt. Nach der Verschiebung zeigt die move-to-Variable auf den Speicherort der Daten im Speicher, und die move-from-Variable wird im Grunde ein Null-Zeiger. Hier könnte ich meinen ersten Fehler machen, indem ich die Bewegungssemantik auf Zeiger zu nahe bringe. Bin ich? Die tatsächliche Frage: Eine Variable wird in einem inneren Bereich erstellt und dann in eine Variable in einem äußeren Bereich verschoben. Dann wird der innere Bereich beendet. Was passiert mit dem Stapel?

Angesichts der oben genannten sollte der Stapelzeiger an seine vorherige Position zurückkehren und den inneren Umfang Speicher freigeben. Dies ist jedoch nicht möglich, da der Speicher des inneren Bereichs immer noch gültig ist, da er jetzt an die äußere Bereichsvariable angehängt ist. Zwischen dem äußeren (möglicherweise globalen) Bereich und dem ehemals inneren Bereichsspeicher kann viel Speicher blockiert/verschwendet sein. Dieser Speicher wird wieder verfügbar, sobald der äußere Bereich beendet wird. Bis dahin ist die Stapelgröße aufgebläht. Ist das wahr? Kann dies vermieden werden? Verhindert der Compiler das?

+0

"Verschiebungssemantik" bedeutet nicht, dass ein Objekt physisch an einen anderen Ort verschoben wird. Es bedeutet nur, dass der von einem Objekt verwaltete Zustand (z. B. ein auf dem Heap zugeordneter Speicherblock, auf dem das Objekt einen Zeiger hält) dem anderen übergeben wird, und zwar auf eine Weise, die durch die Klasse dieses Objekts spezifiziert wird, die oft billiger ist eine vollständige Kopie dieses Staates machen. Dies hat keinen Einfluss darauf, wie der von diesen Objekten belegte Speicher, ob auf dem Stapel oder anderweitig, zugewiesen oder freigegeben wird. –

+0

Genau das ist mein Punkt.Der belegte Speicher bleibt nach dem Verschieben gleich, aber damit der Stapel ordnungsgemäß funktioniert, sollte der gesamte Speicher eines Bereichs freigegeben werden, wenn der Bereich verlassen wird. Vielleicht habe ich es nicht klar erklärt. – bjoern

+0

Die Verschiebungssemantik ist nur für Klassen nützlich, in denen Sie einen Zeiger auf den Heap haben (soweit es Ihnen wichtig ist). Statt einer tiefen Kopie können Sie Ihre Klasse sicher flach kopieren, weil Sie wissen, dass Ihre Besitzrechte an den Heap-Daten allein Ihnen gehören, der vorherige Besitz wurde Ihnen übertragen. So ist die Erinnerung, die dir wichtig ist, wenn sich 'move' bewegt, niemals wirklich im Stapel. Sie kopieren weiterhin Ihre Stack-Objekte (Klassenelemente mit Zeiger auf Heap-Speicher), aber das ist klein und akzeptabel im Vergleich zu einer tiefen Kopie aller Daten im Heap. – Troyseph

Antwort

0

Haftungsausschluss, Laien, vertrackt Analogien und wackelig C++ Wissen zu folgen ...

Ich glaube, ich Ihre Verwirrung verstehen,

[stack frame a] 
std::vector toPopulate; 
    [stack frame b] 
    std::vector toMove; // will be std::moved into `toPopulate` somehow 

, wenn der Stapel Umfang verlässt b und geht zurück auf a, Wie verhindert die move je Kopie, wie Sie eindeutig den Speicher im Stack-Frame verlassen können b ...

Antwort: Es tut nicht! die Stapeldaten für toMove werden in toPopulate kopiert, std::vector speichert Array seinen Inhalt nicht in dem Stapel, es speichert lediglich eine Adresse/einen Zeiger wo sich der Speicher in dem Heap befindet.

Was std::move hier tut sagen zu den vector nicht tief kopieren selbst (nicht die Heap-Daten in einer anderen Platz in der Halde kopieren), kopieren Sie einfach die data Zeiger, vertrauen Sie mir, das ist sicher zu tun , Sicherheit wird zur Kompilierzeit erzwungen.

Also toPopulate ist konstruiert, seine DataCount und dataPointer und was auch immer sonst benötigt wird, um einen std :: vector zu beschreiben, werden in den Heap-Speicher geschrieben/kopiert, aber Ihre Heap-Daten nicht berührt, noch wird es jemals von mehreren gehört std::vectors im Stapel, was in der Tat lästig wäre!

+0

Das macht Sinn und klärt eine weitere Verwirrung von mir bezüglich der Größe des Stapels auf ... Also die tatsächlichen Daten, die ich z. ein STL-Container wird nie auf dem Stapel gespeichert? Nur die nennen wir es Metadaten eines Vektors oder einer Karte ist auf dem Stapel? Das würde in der Tat schnell kopiert und befreit werden. Und würde erklären, warum ich einen Vektor zig oder Hunderte von MB in der Größe auf dem Stapel speichern kann. Ist das richtig? – bjoern

+0

Genau, ich denke die meisten STL-Container funktionieren auf diese Weise. – Troyseph

Verwandte Themen