2014-03-24 14 views
23

Nach N3485 §23.3.2.2:Verschieben Bauer und `std :: array`

(...) die implizite Bewegung Konstruktor und Zuweisungsoperator für Array bewegen verlangen, dass T MoveConstructible sein oder MoveAssignable bzw..

So unterstützt std::array Verschieben Semantik, wenn der Typ seiner Elemente tut. Groß!

Was bedeutet das aber wirklich? Ich neige dazu, diesen Typ als eine sicherere Version eines Arrays darzustellen, das eine STL-kompatible Schnittstelle bereitstellt, aber wenn dies zutrifft, wie kann dann ein seine Elemente verschieben? Kann ich dasselbe mit einem gewöhnlichen Array machen?

Antwort

24

Doch was bedeutet das wirklich?

Dies bedeutet, dass, wenn der Elementtyp beweglich ist, auch der Array-Typ.

std::array<movable, 42> move_from = {...}; 
std::array<movable, 42> move_to = std::move(move_from); // moves all the elements 

Ich neige dazu, diese Art als eine sicherere Version eines Arrays Bild STL-konforme Schnittstelle

Nicht wirklich bietet. Es ist ein Wrapper für ein Array, der dieselbe Semantik wie eine Aggregatklasse aufweist - einschließlich der Fähigkeit, es zu kopieren und zu verschieben.

Wie kann ein move-construct seine Elemente?

In genau der gleichen Weise wie jedes andere Aggregat. Der implizite move-Konstruktor wird alle Elemente einschließlich der Elemente beliebiger Element-Arrays verschieben.

Kann ich dasselbe mit einem gewöhnlichen Array machen?

Nur wenn Sie es in eine Klassenart umhüllen, wie tut.

+1

* "Nur wenn Sie es in eine Klassenart umbrechen" * Es ist also die Tatsache, dass es ein benutzerdefinierter Typ ist, der dieses Verhalten erlaubt ... Interessant. –

+9

@faranwath: In der Tat - die Tatsache, dass benutzerdefinierte Aggregatarten implizit Move-Konstruktoren generiert haben. –

20

Das Verschieben einer unterscheidet sich von der Bewegung einer std::vector. Wenn man eine std::vector in eine andere verschiebt, ist es (manchmal *) möglich, die internen Zeiger einfach neu zu targetieren und zu vermeiden, die Elemente überhaupt zu manipulieren.

Mit std::array ist dies natürlich nicht möglich - seine Elemente haben eine automatische Speicherdauer, sie sind buchstäblich im Inneren des Objekts enthalten.Jedoch kann jeder einzelne von ihnen noch bewegt werden, und das tun die Verschiebungsoperationen unter std::array **.

* Unter der Annahme, die Zuweiser sind kompatibel und nicht verbieten, diesen Vorgang

** Das ist auch das, was Sie mit std::vector erhalten, wenn der Puffer kann nicht nur durch den Zielvektor erneut gehören.

+0

DANKE für die klarste Erklärung. es ist nötig. –

6

Der Standard-Move-Konstruktor für eine (nicht geteilte) Klasse führt eine teilweisen Verschiebung durch. Wenn Sie ein rohe Array-Datenelement verschieben, müssen Sie die einzelnen Elemente des Arrays verschieben, siehe [class.copy]/15.

Daher können Sie eine rohe Array verschieben, indem es innerhalb einer Klasse setzen:

struct wrap 
{ 
    std::string arr[25]; 
}; 

auto w = wrap(); 
auto m = std::move(w); // moves the 25 `std::string`s 

können Sie auch den Umzug Konstruktor der Elemente manuell aufrufen, zum Beispiel:

std::string a[3] = { /*...*/ }; 
std::string b[3] = {std::move(a[0]), std::move(a[1]), std::move(a[2])}; 

Es ist nicht angegeben, wenn std::array ein RAW-Array enthält. Es enthält jedoch Datenelemente der value_type, da es garantiert ein Aggregat ist. Diese Datenelemente werden beim Aufrufen des Verschiebungskonstruktors wie oben beschrieben verschoben.

Wenn die Datenelemente einer std::array nicht MoveConstructible sind, schlägt das Instanziieren des Move-Konstruktors fehl.

+1

* "Daher können Sie ein rohe Array verschieben, indem Sie es in eine Klasse einfügen" * Das wurde von Mike Seymour aufgezeigt, ich war mir dessen nicht bewusst - obwohl jetzt, wo ich darüber nachdenke, Sinn ergibt. –

Verwandte Themen