2013-08-17 8 views
54

Ist dasIst ein `= default`-Move-Konstruktor äquivalent zu einem memberweisen Move-Konstruktor?

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB}    { } 
    Example(const Example& mE) : a{mE.a}, b{mE.b}  { } 
    Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { } 
    Example& operator=(const Example& mE) { a = mE.a; b = mE.b; return *this; } 
    Example& operator=(Example&& mE)  { a = move(mE.a); b = move(mE.b); return *this; } 
} 

entspricht dieser

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB} { } 
    Example(const Example& mE)   = default; 
    Example(Example&& mE)     = default; 
    Example& operator=(const Example& mE) = default; 
    Example& operator=(Example&& mE)  = default; 
} 

?

+0

Dies könnte eine Verdopplung von http://stackoverflow.com/questions/4819936/why-no-default-move-assignment-move-constructor –

+3

@ DieterLücking: Es ist eindeutig nicht, obwohl es über ein ähnliches Thema und einige ist Antworten können sich auf ähnliche Gründe beziehen. Wir werden jedoch nicht jede einzelne Frage zur Bewegungssemantik als Duplikate voneinander schließen. –

+0

Hinweis, ich habe meine Antwort auf diese Frage hinzugefügt, weil ich zu der Zeit nach einem Zitat aus dem Standard gesucht habe, das bewiesen hat, dass sie gleichwertig sind und die akzeptierte Antwort das nicht tut. Also, ich habe gerade das Zitat gefunden und meine Antwort hinzugefügt. –

Antwort

27

Ja beide sind gleich.

Aber

struct Example { 
    int a, b; 
    Example(int mA, int mB) : a{mA}, b{mB} { } 
    Example(const Example& mE)   = default; 
    Example(Example&& mE)     = default; 
    Example& operator=(const Example& mE) = default; 
    Example& operator=(Example&& mE)  = default; 
} 

Diese Version wird ermöglicht es Ihnen, den Körper Definition zu überspringen.

Allerdings müssen Sie einige Regeln beachten, wenn Sie explicitly-defaulted-functions erklären:

8.4.2 Explizit ausgefallene Funktionen [dcl.fct.def.default]

Eine Funktion Definition der Form:

attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ; 

ist eine explizit notleidenden Definition bezeichnet. Eine Funktion, die explizit vorbelegt werden

  • Funktion ein besonderes Mitglied sein,

  • haben die gleiche Funktion Typ deklariert (mit Ausnahme möglicherweise unterschiedliche ref-Qualifikations und der Ausnahme, dass im Falle einer Kopie Konstruktor oder kopiert Zuweisungsoperator kann der Parameter-Typ „Verweis auf nicht-const T“ sein, wo T der Name der Klasse der Member-Funktion ist), als ob es implizit deklariert worden war,

  • keine Standardargumente haben.

+0

Von welchem ​​Dokument zitieren Sie 8.4.2? Weder der C++ 11-Standard noch N3690 enthalten den Text ", und haben keine * Ausnahme-Spezifikation *" in 8.4.2/1. Sie sagen beide in 8.4.2/2: "Eine explizit voreingestellte Funktion kann nur dann als" consxpr "deklariert werden, wenn sie implizit als" constexpr "deklariert wurde und nur dann eine explizite * exception-specification * aufweisen kann kompatibel (15.4) mit der * exception-specification * der impliziten Deklaration. " – Casey

+1

@Casey Guter Fang! Ich habe das N3242 zitiert ... Ich habe meine Dokumente durcheinander gebracht ... Ich habe meinen Beitrag aktualisiert, um das N3690 zu zitieren! Danke, dass du darauf hingewiesen hast! –

+1

Wenn ich einen Verschiebungskonstruktor und einen Zuweisungsoperator auf '= default' setze, kann ich dann mit dem Objekt tauschen? Muss ich den Konstruktor nicht als 'noexcept' deklarieren? Ich habe versucht, beide "noexcept" und "= default" für beide, aber das würde nicht kompilieren. – VF1

0

abgesehen von sehr pathologischen Fällen ... JA.

Um genauer zu sein, müssen Sie auch mögliche Basen Example haben, mit genau den gleichen Regeln. Zuerst die Basen - in der Deklarationsreihenfolge - dann die Mitglieder, immer in der Deklarationsreihenfolge.

14

Ja, ein Verzug geratener Zug Konstruktor wird ein Mitglied klugen Schachzug von seiner Basis und Mitgliedern durchführt, so:

Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { } 

entspricht:

Example(Example&& mE)     = default; 

können wir siehe hierzu unter draft C++11 standard Abschnitt 12.8Kopieren und Verschieben von Klassenobjekten paragra ph , die sagt (Hervorhebung von mir geht nach vorn):

Ein Kopieren/Verschieben Konstruktor, der Verzug geraten ist und nicht als gelöscht definiert implizit definiert, wenn es odrused wird (3.2) oder wenn es ist explizit nach der ersten Deklaration voreingestellt. [Anmerkung: Der Konstruktor copy/move ist implizit auch dann definiert, wenn die Implementierung ihre odr-use (3.2, 12.2) verwendet. -Ende note] [...]

und Absatz die sagt:

Der implizit definierte Kopieren/Verschieben Konstruktor für eine nicht gewerkschaftlich Klasse X a führt Elementweise kopieren/Verschieben seiner Basen und Mitglieder. [Hinweis: Klammer-oder-Gleich-Initialisierer von nicht statischen Datenelementen werden ignoriert. Siehe auch das Beispiel in 12.6.2. -end note] Die Reihenfolge der Initialisierung ist die gleiche wie die Reihenfolge der Initialisierung von Basen und Mitglieder in einem benutzerdefinierten Konstruktor (siehe 12.6.2). Sei x entweder der Parameter des Konstruktors oder, für den Move-Konstruktor, ein xvalue, der sich auf den Parameter bezieht. Jede Basis oder nicht-statisches Datenelement kopiert/verschoben auf die Weise, die seine Art:

  • , wenn das Element ein Array, wobei jeder Element-direct initialisiert mit dem entsprechenden Subobjekt von x;
  • Wenn ein Element m den rvalue-Referenztyp T & & hat, wird es direkt mit static_cast (x.m) initialisiert;
  • andernfalls wird die Basis oder das Element direkt mit der entsprechenden Basis oder dem Member von x initialisiert.

virtuelle Basisklasse Subobjekte wird nur einmal durch den implizit definierte Kopieren/Verschieben Konstruktor (siehe 12.6.2) initialisiert werden.

0

Ist das Äquivalent zu dieser

Ja. Aber es ist nur gültig für Klassen, die nicht bewegliche Mitglieder haben.Schauen Sie sich dieses Beispiel:

#include <iostream> 

struct nonmovable 
{ 
    nonmovable() = default; 

    nonmovable(const nonmovable &) = default; 
    nonmovable(  nonmovable &&) = delete; 
}; 

struct movable 
{ 
    movable() = default; 

    movable(const movable &) { std::cerr << "copy" << std::endl; } 
    movable(  movable &&) { std::cerr << "move" << std::endl; } 
}; 

struct has_nonmovable 
{ 
    movable a; 
    nonmovable b; 

    has_nonmovable() = default; 

    has_nonmovable(const has_nonmovable &) = default; 
    has_nonmovable(  has_nonmovable &&) = default; 
}; 

int main() 
{ 
    has_nonmovable c; 
    has_nonmovable d(std::move(c)); // prints copy 
} 

Er druckt:

copy 

http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb

Also, wenn eine Klasse auch nur ein einziges nicht-bewegliches Element hat, wird die explizit vorgegeben bewegen Konstruktor die Kopierkonstruktoren verwenden für alle Mitglieder, auch für diejenigen, die den Move-Konstruktor haben.

Mitglieder müssen jedoch Move-Konstruktoren nicht explizit definiert oder explizit defaultiert haben. Wenn der move-Konstruktor überhaupt nicht deklariert ist, wird der move -Konstruktor für Elemente verwendet, die den move-Konstruktor haben, und der copy-Konstruktor wird für members verwendet, die den move-Konstruktor nicht definieren. Siehe Beispiel:

#include <iostream> 

struct nonmovable 
{ 
    nonmovable() = default; 

    nonmovable(const nonmovable &) { std::cerr << "nonmovable::copy" << std::endl; } 
    //nonmovable(  nonmovable &&) = delete; 
}; 

struct movable 
{ 
    movable() = default; 

    movable(const movable &) { std::cerr << "movable::copy" << std::endl; } 
    movable(  movable &&) { std::cerr << "movable::move" << std::endl; } 
}; 

struct has_nonmovable 
{ 
    movable a; 
    nonmovable b; 

    has_nonmovable() = default; 

    has_nonmovable(const has_nonmovable &) = default; 
    has_nonmovable(  has_nonmovable &&) = default; 
}; 

int main() 
{ 
    has_nonmovable c; 
    has_nonmovable d(std::move(c)); 
} 

Er druckt:

movable::move 
nonmovable::copy 

http://coliru.stacked-crooked.com/a/fda51f29a4b92881

Es Klassen sind, die beweglich sind, aber nicht kopierbar (z unique_ptr). Es gibt Klassen, die kopierbar sind und den Kopierkonstruktor zum Verschieben verwenden. Aber ich kenne keinen Grund, eine Klasse zu erstellen, die kopierbar ist, aber explizit move constructor gelöscht hat.

Verwandte Themen