Wie kann ich die Konstruktion eines Objekts verbieten? Ich markiere = delete;
alle relevanten Sonderfunktionen wie folgt:
Aber x
, y
und *z
können noch existieren. Was ist zu tun? Ich bin an beiden Fällen interessiert; statische / Stapelzuweisung und Heap-Zuweisung.
Wenn Sie die Klasse nicht instanziieren möchten, können Sie einfach private Konstruktoren deklarieren:
%Vor% Und% NotInstantiable
nicht weiter definieren. Dies kann jetzt nicht instanziiert werden, da der Konstruktor zuerst private
ist, aber auch keine Definition für den Konstruktor angegeben wurde.
Das zweite Hindernis, um die NotInstantiable
zu instantiieren, würde zum Beispiel diese Möglichkeit verbieten, die ansonsten ein bekanntes Muster ist:
Wenn Sie nur static
Mitglieder haben möchten, dann schreiben Sie namespace A
anstatt struct A
. Der nachfolgende Code ist syntaktisch ähnlich.
Um die Erstellung einer Instanz einer Klasse zu verhindern, sollten Sie sie abstrakt machen. (Fügen Sie eine reine virtuelle Funktion ein). Aber dadurch wird eine v-Tabelle in Ihre Klasse eingeführt, die Sie vielleicht nicht möchten.
Um die Client-Code-Instantiierung einer Klasse vollständig zu verhindern, können Sie im Allgemeinen die Klasse final
und entweder
Machen Sie die Konstruktoren nicht public
oder
Löschen Sie die Konstruktoren und stellen Sie sicher, dass die Klasse kein Aggregat ist oder
Fügen Sie eine reine virtuelle Elementfunktion hinzu (z. B. machen Sie den Destruktor rein virtuell), um die Klasse abstrakt zu machen.
Die Deklaration der Klasse final
ist erforderlich, wenn die nicht public
protected
und die abstrakte Klasse ist, um die Instanziierung eines Basisklassenunterobjekts einer abgeleiteten Klasse zu verhindern.
Um die Instanziierung teilweise zu verhindern, können Sie
verwendenpublic
. Dies verhindert automatische und statische Variablen, verhindert jedoch nicht die dynamische Zuweisung mit new
.
operator new
) nicht public
. Dies verhindert die dynamische Zuweisung über einen normalen new
-Ausdruck im Client-Code, bietet jedoch keine automatischen und statischen Variablen oder Unterobjekte anderer Objekte und verhindert nicht die dynamische Zuweisung über ::new
- Ausdruck, der die globale Zuordnungsfunktion verwendet.
Es gibt auch andere relevante Techniken, wie eine Zuordnungsfunktion mit zusätzlichen Argumenten, die new
-Ausdrücke übermäßig kompliziert und unpraktisch machen. Ich habe das einmal verwendet, um die Verwendung eines speziellen Makros zu erzwingen, um Objekte, z. für eine shared-from-this-Klasse . Aber das war in der Zeit vor C ++ 11 Unterstützung für die Weiterleitung von Argumenten; Heutzutage kann eine gewöhnliche Funktion die Aufgabe übernehmen, und eine solche Funktion kann als friend
der Klasse erstellt werden.
Die Tatsache, dass der Code mit mindestens einer Version des Clang-Compilers kompiliert mit -std=gnu++1z
, ist auf einen Fehler und / oder eine Spracherweiterung in diesem Compiler zurückzuführen.
Der Code sollte nicht kompiliert werden, da er den Standardkonstruktor aufruft, der gelöscht wurde. Und es kompiliert nicht mit z.B. MinGW g ++ 5.1.0, auch mit -std=gnu++1z
.
Die Tatsache, dass der Code mit mindestens einer Version des Clang-Compilers kompiliert wird mit -std=gnu++1z
, kann aufgrund eines Fehlers und / oder einer Spracherweiterung in diesem Compiler sein. Was das richtige Verhalten ist, ist unklar, weil
Obwohl der Code mit clang und mit Visual C ++ 2015 kompiliert wird, kompiliert er nicht mit z. MinGW g ++ 5.1.0, sogar mit -std=gnu++1z
.
Intuitiv wäre die delete
bedeutungslos, wenn der Code kompiliert werden müsste, aber viele sinnlose Konstrukte sind in C ++ erlaubt.
Es besteht die Frage, ob die Klasse ein Aggregat ist (in diesem Fall führt der new
-Ausdruck eine Aggregat-Initialisierung durch), die davon abhängt, ob der gelöschte Standardkonstruktor als vom Benutzer bereitgestellt Und als Benutzer TartanLlama , der in Kommentaren erläutert wird, sind die Anforderungen für vom Benutzer bereitgestellte
" Eine spezielle Memberfunktion ist vom Benutzer bereitgestellt , wenn sie vom Benutzer deklariert wurde und nicht explizit bei seiner ersten Deklaration voreingestellt oder gelöscht.
i.e. Obwohl der delete
des Standardkonstruktors im Beispiel dieser Frage diesen Konstruktor deklariert, wird er nicht vom Benutzer bereitgestellt (und dito für die anderen Mitglieder), und daher ist die Klasse ein Aggregat.
Der einzige Fehlerbericht, den ich über diese Formulierung finden kann, ist DR 1355 , die jedoch nur ein Problem mit der Verwendung der Wörter "besonderes Mitglied" betrifft, und schlägt vor, diese Wörter fallen zu lassen. Aber in Anbetracht der Wirkung dieser Frage und der Tatsache, dass eine Funktion nur in der ersten Deklaration gelöscht werden kann, ist der Wortlaut seltsam.
Zusammenfassend, formell ab C ++ 11 (Ich habe C ++ 14 nicht überprüft), sollte der Code kompilieren. Dies kann jedoch ein Fehler in der Norm sein, wobei die Formulierung die Absicht nicht widerspiegelt. Und da MinGW g ++ 5.1.0 den Code nicht kompiliert, ist es ab Oktober 2015 nicht sinnvoll, sich auf die Code-Kompilierung zu verlassen.
Im Wesentlichen wird dies kompiliert und ist erlaubt, weil der Typ A
ein Aggregattyp ist und die Aggregat-Initialisierung keine Standardkonstruktoren verwendet.
Klassentyp (normalerweise struct oder union), der
hat
- keine privaten oder geschützten Mitglieder
- keine vom Benutzer bereitgestellten Konstruktoren (explizit vordefinierte oder gelöschte Konstruktoren sind erlaubt) (seit C ++ 11)
- keine Basisklassen
- keine virtuellen Mitgliedsfunktionen
Wenn Sie eine der oben genannten Angaben angeben, würde dies zu einer Nicht-Aggregation führen, sodass die aggregierte Initialisierung nicht angewendet werden kann. Geben Sie es einen privaten Benutzer definierten (und nicht implementiert) Konstruktor tun.
%Vor% Als eine Randnotiz; Ich hoffe, das ist ein Fehler in den Sprachspezifikationen. Auf den ersten Blick dachte ich, dass das nicht kompilieren sollte, aber es tut es. Eine der Motivationen für =delete
bestand darin, den C ++ 03-Trick zu vermeiden, die Konstruktoren zu deklarieren, um sie "zu verstecken" und somit unbrauchbar zu sein. Ich würde erwarten, dass ein =delete
im Standardkonstruktor die Erstellung von Klassen effektiv verbietet (außerhalb anderer benutzerdefinierter Konstruktoren).
Zum leichteren Lesen und klarerer Absicht sollten Sie sogar eine leere Basisklasse in Betracht ziehen;
%Vor%Vielleicht ist es am einfachsten, hier zum C ++ 03-Stil zurückzukehren und den Standardkonstruktor privat zu machen;
%Vor%Tags und Links c++ c++11 memory-management c++14 memory-layout