wake-up-neo.net

Was bedeutet "default" nach einer Funktionsdeklaration einer Klasse?

Ich habe gesehen, dass default neben Funktionsdeklarationen in einer Klasse verwendet wird. Was tut es?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};
182
Paul Manta

Es ist eine neue C++ 11-Funktion .

Dies bedeutet, dass Sie die vom Compiler generierte Version dieser Funktion verwenden möchten, sodass Sie keinen Rumpf angeben müssen.

Sie können auch = delete verwenden, um anzugeben, dass not nicht möchten, dass der Compiler diese Funktion automatisch generiert.

Mit der Einführung von Verschiebungskonstruktoren und Verschiebungszuweisungsoperatoren wurden die Regeln, wann automatische Versionen von Konstruktoren, Destruktoren und Zuweisungsoperatoren erzeugt werden, ziemlich komplex. Die Verwendung von = default und = delete macht die Sache einfacher, da Sie sich nicht an die Regeln erinnern müssen: Sie sagen nur, was Sie wollen.

213
Peter Alexander

Dies ist eine neue C++ 0x-Funktion, die den Compiler anweist, die Standardversion des jeweiligen Konstruktors oder Zuweisungsoperators zu erstellen, d. H. Derjenigen, die nur die Kopie oder die Verschiebungsaktion für jedes Element ausführt. Dies ist nützlich, da der Verschiebungskonstruktor nicht immer standardmäßig generiert wird (z. B. wenn Sie einen benutzerdefinierten Destruktor haben), im Gegensatz zum Kopierkonstruktor (und ebenfalls für die Zuweisung). Wenn jedoch nichts Unauffälliges beim Schreiben vorhanden ist, sollten Sie das lieber Compiler handhaben, als es jedes Mal selbst auszusprechen.

Beachten Sie außerdem, dass kein Standardkonstruktor generiert wird, wenn Sie einen anderen Konstruktor angeben, der nicht dem Standard entspricht. Wenn Sie auch noch den Standardkonstruktor verwenden möchten, können Sie diese Syntax verwenden, damit der Compiler einen solchen erstellt.

In einem anderen Anwendungsfall gibt es mehrere Situationen, in denen ein Kopienkonstruktor nicht implizit generiert wird (z. B. wenn Sie einen benutzerdefinierten Bewegungskonstruktor bereitstellen). Wenn Sie immer noch die Standardversion wünschen, können Sie diese mit dieser Syntax anfordern.

Einzelheiten finden Sie in Abschnitt 12.8 der Norm.

41
Kerrek SB

Es ist neu in C++ 11, siehe hier . Dies kann sehr nützlich sein, wenn Sie einen Konstruktor definiert haben, für die anderen jedoch Standardwerte verwenden möchten. Vor C++ 11 müssten Sie alle Konstruktoren definieren, sobald Sie einen definiert haben, auch wenn sie den Standardwerten entsprechen.

Beachten Sie außerdem, dass es in bestimmten Situationen nicht möglich ist, einen benutzerdefinierten Standardkonstruktor bereitzustellen, der sich genauso wie der Compiler verhält, der unter der Initialisierung default und value synthetisiert wurde. Mit default können Sie dieses Verhalten zurückbekommen.

18
juanchopanza

Ein anderer Anwendungsfall, den ich in diesen Antworten nicht erwähnt sehe, ist, dass Sie leicht die Sichtbarkeit eines Konstruktors ändern können. Beispielsweise möchten Sie vielleicht, dass eine Friend-Klasse auf den Kopierkonstruktor zugreifen kann, aber nicht, dass er öffentlich verfügbar ist.

10
dshin

C++ 17 N4659 Standardentwurf

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "Explizit voreingestellte Funktionen":

1 Eine Funktionsdefinition der Form:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

wird als explizit vorgegebene Definition bezeichnet. Eine explizit voreingestellte Funktion soll

  • (1.1) - eine besondere Memberfunktion sein,

  • (1.2) - haben den gleichen deklarierten Funktionstyp (mit Ausnahme von möglicherweise abweichenden Ref-Qualifizierern und mit der Ausnahme, dass in Der Fall eines Kopierkonstruktors oder Kopierzuweisungsoperators der Parametertyp "Verweis auf Nichtkonst T ”, wobei T der Name der Klasse der Member-Funktion ist), als wäre sie implizit deklariert worden, und

  • (1.3) - keine Standardargumente.

2 Eine explizit voreingestellte Funktion, die nicht als gelöscht definiert ist, kann nur dann als constexpr deklariert werden, wenn sie wurden implizit als constexpr deklariert. Wenn eine Funktion in ihrer ersten Deklaration explizit vorgegeben ist, ist sie implizit als "constexpr" betrachtet, wenn die implizite Deklaration.

3 Wenn eine Funktion, die explizit als Standard festgelegt ist, mit einem Noexcept-Bezeichner deklariert wird, der nicht dasselbe .__ erzeugt. Ausnahmespezifikation als implizite Deklaration (18.4), dann

  • (3.1) - Wenn die Funktion bei ihrer ersten Deklaration explizit vorgegeben ist, wird sie als gelöscht definiert.

  • (3.2) - sonst ist das Programm schlecht ausgebildet.

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

- Ende Beispiel]

5 Explizit voreingestellte Funktionen und implizit deklarierte Funktionen werden zusammen als Standardfunktionen und .__ bezeichnet. Die Implementierung muss implizite Definitionen enthalten (15.1, 15.4, 15.8), was die Definition von .__ bedeuten kann. sie als gelöscht. Eine Funktion wird vom Benutzer bereitgestellt, wenn sie vom Benutzer deklariert wurde und nicht explizit als Standard festgelegt oder gelöscht wurde auf seiner ersten Erklärung. Eine vom Benutzer bereitgestellte explizit vorgegebene Funktion (d. H. Explizit als Standardwert nach der ersten -Deklaration angegeben) wird an der Stelle definiert, an der sie explizit als Standardwert festgelegt ist. wenn eine solche Funktion implizit als .__ definiert ist. gelöscht, ist das Programm schlecht geformt. [Hinweis: Wenn Sie eine Funktion nach ihrer ersten Deklaration als Standard deklarieren, kann sorgen für eine effiziente Ausführung und präzise Definition und ermöglichen gleichzeitig eine stabile binäre Schnittstelle für einen sich entwickelnden Code Base. - 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

- Ende Beispiel]

Dann stellt sich natürlich die Frage, welche Funktionen implizit deklariert werden können und wann dies der Fall ist.