Ich habe default
neben Funktionsdeklarationen in einer Klasse verwendet gesehen. Was tut es?
class C {
C(const C&) = default;
C(C&&) = default;
C& operator=(const C&) & = default;
C& operator=(C&&) & = default;
virtual ~C() { }
};
Ich habe default
neben Funktionsdeklarationen in einer Klasse verwendet gesehen. Was tut es?
class C {
C(const C&) = default;
C(C&&) = default;
C& operator=(const C&) & = default;
C& operator=(C&&) & = default;
virtual ~C() { }
};
Antworten:
Es ist eine neue C ++ 11-Funktion .
Dies bedeutet, dass Sie die vom Compiler generierte Version dieser Funktion verwenden möchten, sodass Sie keinen Body angeben müssen.
Sie können auch verwenden , = delete
um anzugeben , dass Sie nicht wollen , dass der Compiler diese Funktion automatisch zu generieren.
Mit der Einführung von Verschiebungskonstruktoren und Verschiebungszuweisungsoperatoren sind die Regeln für die Generierung automatischer Versionen von Konstruktoren, Destruktoren und Zuweisungsoperatoren recht komplex geworden. Verwenden = default
und = delete
erleichtert die Arbeit, da Sie sich nicht an die Regeln erinnern müssen: Sie sagen nur, was passieren soll.
= delete
ist stärker: Es bedeutet, dass die Verwendung dieser Funktion verboten ist, obwohl sie immer noch an der Überlastungsauflösung beteiligt ist.
Dies ist eine neue C ++ 0x-Funktion, die den Compiler anweist, die Standardversion des jeweiligen Konstruktors oder Zuweisungsoperators zu erstellen, dh die, die nur die Kopier- oder Verschiebeaktion für jedes Mitglied ausführt. Dies ist nützlich, da der Verschiebungskonstruktor im Gegensatz zum Kopierkonstruktor (und ebenfalls für die Zuweisung) nicht immer standardmäßig generiert wird (z. B. wenn Sie einen benutzerdefinierten Destruktor haben). Wenn jedoch nichts nicht triviales zu schreiben ist, ist es besser, das zuzulassen Der Compiler handhabt es, als es jedes Mal selbst zu formulieren.
Beachten Sie auch, dass ein Standardkonstruktor nicht generiert wird, wenn Sie einen anderen nicht standardmäßigen Konstruktor angeben. Wenn Sie auch weiterhin den Standardkonstruktor möchten, können Sie diese Syntax verwenden, damit der Compiler einen erstellt.
Als weiteren Anwendungsfall gibt es mehrere Situationen, in denen ein Kopierkonstruktor nicht implizit generiert wird (z. B. wenn Sie einen benutzerdefinierten Verschiebungskonstruktor bereitstellen). Wenn Sie weiterhin die Standardversion möchten, können Sie diese mit dieser Syntax anfordern.
Einzelheiten finden Sie in Abschnitt 12.8 des Standards.
operator new/new[]
, operator delete/delete[]
und deren Überlastung.
Es ist neu in C ++ 11, siehe hier . Dies kann sehr nützlich sein, wenn Sie einen Konstruktor definiert haben, aber die Standardeinstellungen für die anderen verwenden möchten. Vor C ++ 11 müssten Sie alle Konstruktoren definieren, sobald Sie einen definiert haben, auch wenn sie den Standardeinstellungen entsprechen.
Beachten Sie auch , dass in bestimmten Situationen ist es unmöglich, einen benutzerdefinierten Standardkonstruktor zur Verfügung zu stellen , dass verhält sich die gleichen wie die Compiler eine sowohl unter synthetisierte Standard und Wert der Initialisierung. default
ermöglicht es Ihnen, dieses Verhalten zurückzubekommen.
Ein weiterer Anwendungsfall, den ich in diesen Antworten nicht sehe, besteht darin, dass Sie die Sichtbarkeit eines Konstruktors leicht ändern können. Zum Beispiel möchten Sie vielleicht, dass eine Freundesklasse auf den Kopierkonstruktor zugreifen kann, aber Sie möchten nicht, dass er öffentlich verfügbar ist.
C ++ 17 N4659 Standardentwurf
https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Explizit voreingestellte Funktionen":
1 Eine Funktionsdefinition des Formulars:
attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;
wird als explizit voreingestellte Definition bezeichnet. Eine explizit voreingestellte Funktion soll
(1.1) - eine spezielle Mitgliedsfunktion sein,
(1.2) - haben denselben deklarierten Funktionstyp (mit Ausnahme möglicherweise unterschiedlicher Referenzqualifizierer und mit der Ausnahme, dass im Fall eines Kopierkonstruktors oder eines Kopierzuweisungsoperators der Parametertyp "Referenz auf Nicht-Konstante T" sein kann, wobei T ist den Namen der Klasse der Mitgliedsfunktion), als ob sie implizit deklariert worden wäre, und
(1.3) - keine Standardargumente haben.
2 Eine explizit voreingestellte Funktion, die nicht als gelöscht definiert ist, kann nur dann als constexpr deklariert werden, wenn sie implizit als constexpr deklariert worden wäre. Wenn eine Funktion bei ihrer ersten Deklaration explizit voreingestellt ist, wird sie implizit als constexpr betrachtet, wenn die implizite Deklaration wäre.
3 Wenn eine explizit voreingestellte Funktion mit einem noexcept-Spezifizierer deklariert wird, der nicht dieselbe Ausnahmespezifikation wie die implizite Deklaration (18.4) erzeugt, dann
(3.1) - Wenn die Funktion bei ihrer ersten Deklaration explizit voreingestellt ist, wird sie als gelöscht definiert.
(3.2) - Andernfalls ist das Programm fehlerhaft.
4 [Beispiel:
struct S { constexpr S() = default; // ill-formed: implicit S() is not constexpr S(int a = 0) = default; // ill-formed: default argument void operator=(const S&) = default; // ill-formed: non-matching return type ~ S() noexcept(false) = default; // deleted: exception specification does not match private: int i; // OK: private copy constructor S(S&); }; S::S(S&) = default; // OK: defines copy constructor
- Beispiel beenden]
5 Explizit voreingestellte Funktionen und implizit deklarierte Funktionen werden gemeinsam als voreingestellte Funktionen bezeichnet, und die Implementierung muss implizite Definitionen für sie bereitstellen (15.1 15.4, 15.8), was bedeuten kann, dass sie als gelöscht definiert werden. Eine Funktion wird vom Benutzer bereitgestellt, wenn sie vom Benutzer deklariert und bei ihrer ersten Deklaration nicht explizit als Standard festgelegt oder gelöscht wurde. Eine vom Benutzer bereitgestellte explizit voreingestellte Funktion (dh explizit voreingestellte Funktion nach ihrer ersten Deklaration) wird an dem Punkt definiert, an dem sie explizit voreingestellt ist. Wenn eine solche Funktion implizit als gelöscht definiert ist, ist das Programm fehlerhaft. [Hinweis: Das Deklarieren einer Funktion als Standard nach ihrer ersten Deklaration kann eine effiziente Ausführung und präzise Definition ermöglichen und gleichzeitig eine stabile binäre Schnittstelle zu einer sich entwickelnden Codebasis ermöglichen. - Endnote]
6 [Beispiel:
struct trivial { trivial() = default; trivial(const trivial&) = default; trivial(trivial&&) = default; trivial& operator=(const trivial&) = default; trivial& operator=(trivial&&) = default; ~ trivial() = default; }; struct nontrivial1 { nontrivial1(); }; nontrivial1::nontrivial1() = default; // not first declaration
- Beispiel beenden]
Dann ist natürlich die Frage, welche Funktionen implizit deklariert werden können und wann dies geschieht, was ich unter erklärt habe: