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.
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
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. –