2017-12-31 135 views
2

Was ist der Unterschied eines implizit definierten und explizit deklarierten Standard-/Kopierkonstruktors? erklärte ExplizitImplizit definiert vs Explizit deklarierter Konstruktor

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
    road() = default; 
    road(const & road c_road) = default; 
    road(road && m_road); 
    }; 

Implizit

struct road{ 
std::string id; 
std::string type; 
std::vector<int> nodes; 
road(road && m_road); 
}; 

auch definiert, was der Unterschied von der Definition meiner eigenen Konstrukteuren ist wie

road::road(){} 

road::road(const road & c_road):id(c_road.id)), type(c_road.type)), 
    nodes(c_road.nodes){} 

Meine Frage ist, brauche ich eine Standard-contructor ausdrücklich zu erklären, (= Standard; Version) oder sollte ich mich nur auf den impliziten verlassen? Ist irgendeine Version in irgendeiner Weise schneller oder sicherer? Ist irgendeine Version "falsch"?

Antwort

1

Vielleicht möchten Sie in die "Rule of Zero" schauen. Ihre Klasse benötigt keine Konstruktoren, da Ihre Klasse eine Memberwise-Kopie ausführt, für die Ihre Member bereits Konstruktoren für Kopieren/Verschieben definiert haben. Es wäre eine andere Geschichte, wenn Sie eine Ressource verwalten oder schwierigere Typen behandeln müssten. Idealerweise wie diese Klasse aussehen:

struct road{ 
    std::string id; 
    std::string type; 
    std::vector<int> nodes; 
}; 

Wenn Sie vom Benutzer erklären den Kopierkonstruktor aber den Umzug Konstruktor auslassen, wird der Compiler nicht den Umzug Konstruktor für Sie generieren. Du brauchst also alle drei. Wenn Sie sich entscheiden, die Zuweisungsoperatoren zu implementieren, müssen Sie die Zuordnung kopieren/verschieben. Dies wird als Regel von 3/5 bezeichnet. Halten Sie es einfach und definieren Sie nur, was Sie brauchen.

+0

Ich denke, ich würde hinzufügen: Das Hinzufügen eines Konstruktors, der nicht kopieren (oder verschieben) ist ** nicht ** verhindert, dass der Compiler kopieren (und verschieben) Konstruktoren. – Zereges

+0

Um zu verhindern, dass der Compiler unerwünschte Ctors oder Zuweisungen generiert, verwenden Sie "... = delete;" Erklärungen. Beispiel: "T (const T &) = löschen;" die Kopie ctor oder "T & operator = (const T &&) = delete;" Bewegungszuweisung verbieten. –

0

Explizit voreingestellt (inline) vs implizit voreingestellt: Es gibt hier im Allgemeinen sehr wenig Unterschied. Es ist meist eine stilistische Entscheidung. Persönlich, für kleine Klassen (< 1 Bildschirm) würde ich wahrscheinlich nicht stören, da es einfach genug ist, um zu sehen, dass sie nirgendwo definiert sind, und es fügt eine Menge Länge der Klasse hinzu.

Für längere, wichtigere Klassen ist es schön, explizit zu sein. Dies teilt dem Benutzer sofort mit, ob es Wert Semantik (zumindest beweglich) oder Identität Semantik (unbeweglich), ob es kopierbar ist, ob es unveränderlich sein kann (in diesem Fall ist es nicht zulassbar), etc.

One real Unterschied ist, dass wenn Sie einige der speziellen Mitglieder deklarieren, andere nicht implizit generiert werden. Das häufigste Beispiel ist, wenn Sie den Kopierkonstruktor/die Kopierfunktion selbst implementieren müssen. Dadurch wird die automatische Generierung des Verschiebungskonstruktors/-zuweisung deaktiviert. Sie müssten diese also explizit voreinstellen (wenn Sie die Standardeinstellungen wünschen). Ein weiterer wichtiger Unterschied, über den viele Leute hinwegglauben: Wenn Ihre Klasse in .h- und .cpp-Dateien unterteilt ist (wie die meisten Nicht-Template-Klassen sein sollten), führen beide Ansätze dazu, dass der gesamte Code in der Klasse generiert wird Header. Das verlangsamt die Zusammenstellung. So ein dritte Ansatz ist, dies zu tun:

// .h file 
struct Foo { 
    Foo(const Foo&); // declare, but not define 
}; 

// .cpp 
Foo::Foo(const Foo&) = default; 

Dies geschieht immer noch die Vorteile der erzeugten Mitglieder, sondern hält Code in der CPP, wo Sie es wollen. Also, für große, Nicht-Template-Klassen, möchten Sie nur =delete, oder Dinge deklarieren, aber nicht =default oder lassen Sie sie implizit generiert werden!

Soweit eigene spezielle Mitglieder definieren geht: Sie sollten die speziellen Mitglieder nie selbst definieren, wenn die Standardeinstellungen funktionieren. Und Sie sollten versuchen, die Standardeinstellungen funktionieren zu lassen. Wenn Sie einen Konstruktor selbst definieren, müssen Sie jedes Mitglied normalerweise einmal erwähnen.Wenn Sie Mitglieder hinzufügen oder entfernen, führt dies zu Wartungsarbeiten, einschließlich einiger, die stillschweigend vergessen werden können. Siehe die Null-Regel: http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/.

Ein Sonderfall: der Standardkonstruktor. Es wird nicht implizit generiert, wenn Sie andere Konstruktoren haben. Dann, wenn Sie es zurück wollen, scheint es =default es einfach zu sein, und es einfach trivial zu definieren. Diese sind nicht gleich. Insbesondere zählt Letzteres immer noch als ein benutzerdefinierter Konstruktor und es bedeutet zum Beispiel, dass die Klasse niemals als trivially_constructible betrachtet wird und daher nicht trivial ist und daher nicht pod ist. Dies kann bei einigen Anwendungen wichtig sein.

+0

Vielen Dank. Ihr Link war besonders hilfreich, ich denke, dass mein C++ - Wissen jetzt vollständiger ist. Ich habe deine Antwort nicht akzeptiert, nur weil der andere Benutzer den Repräsent wahrscheinlich mehr braucht als du :). Könntest du bitte etwas zur Semantik von Werten/Identität erklären? – Konstantinoscs

+0

@Kkonstantinoscs Nun, Wert Semantik ist wie eine ganze Zahl: Sie können es herum kopieren, und Gleichheit wird basierend auf dem Wert der ganzen Zahl bestimmt. Insbesondere polymorphe Klassen haben möglicherweise keine Wertesemantik; Wenn Sie etwas durch den Basiszeiger halten, können Sie es möglicherweise nicht kopieren, und oft sind sie groß und komplex, so dass ein einfacher, wertbasierter Gleichheitsvergleich auch nicht einfach ist. Sie können also wählen, dass eine solche Klasse nicht kopierbar gemacht werden kann, und ihnen nur die Gleichheit über die Identität geben (wenn sie das exakt gleiche Objekt sind). Es ist ein großes Thema, wahrscheinlich möchte Google :-). –

Verwandte Themen