class my_class
{
...
my_class(my_class const &) = delete;
...
};
Was macht = delete
in diesem Zusammenhang bedeuten?
Gibt es andere "Modifikatoren" (außer = 0
und = delete
)?
Das Löschen einer Funktion ist eine C++ 11-Funktion :
Die gebräuchliche Redewendung des "Kopierverbots" kann nun direkt ausgedrückt werden:
class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
[...]
Der Mechanismus "Löschen" kann für jede Funktion verwendet werden. Zum Beispiel können wir eine unerwünschte Konvertierung wie folgt beseitigen:
struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less };
= 0
bedeutet, dass eine Funktion rein virtuell ist und Sie kein Objekt aus dieser Klasse instanziieren können. Sie müssen daraus ableiten und diese Methode implementieren= delete
bedeutet, dass der Compiler diese Konstruktoren nicht für Sie generiert. AFAIK dies ist nur auf Kopierkonstruktor und Zuweisungsoperator erlaubt. Aber ich bin nicht so gut im kommenden Standard.Dieser Auszug aus der C++ - Programmiersprache [4. Auflage] - Bjarne Stroustrup spricht über das eigentliche Ziel dahinter mit =delete
:
Das Verwenden der Standardkopie oder -verschiebung für eine Klasse in einer Hierarchie ist normalerweise ein Katastrophe: Wenn nur ein Zeiger auf eine Basis angegeben wird, wissen wir einfach nicht, welche Mitglieder die abgeleitete Klasse hat (§3.2.2). Daher können wir nicht wissen, wie wir sie kopieren sollen . Daher ist es normalerweise am besten, die standardmäßigen Kopier- und Verschiebevorgänge zu löschen, dh die Standarddefinitionen dieser beiden Vorgänge zu entfernen:
class Shape { public: Shape(const Shape&) =delete; // no copy operations Shape& operator=(const Shape&) =delete; Shape(Shape&&) =delete; // no move operations Shape& operator=(Shape&&) =delete; ˜Shape(); // ... };
Nun wird ein Versuch, eine Form zu kopieren, vom Compiler abgefangen.
Das
=delete
Mechanismus ist allgemein, das heißt, er kann verwendet werden, um jede Operation zu unterdrücken
Gibt es andere "Modifikatoren" (außer
= 0
und= delete
)?
Da es so aussieht, als hätte niemand diese Frage beantwortet, sollte ich erwähnen, dass es auch =default
.
= delete
ist eine in C++ 11 eingeführte Funktion. Nach =delete
Diese Funktion darf nicht aufgerufen werden.
Im Detail.
Angenommen, in einer Klasse.
Class ABC{
Int d;
Public:
ABC& operator= (const ABC& obj) =delete
{
}
};
Beim Aufrufen dieser Funktion für die Zuweisung von Objekten ist dies nicht zulässig. Bedeutet, dass der Zuweisungsoperator das Kopieren von einem Objekt auf ein anderes einschränken wird.
Die Codierungsstandards, mit denen ich gearbeitet habe, hatten für die meisten Klassendeklarationen die folgenden Eigenschaften.
// coding standard: disallow when not used
T(void) = delete; // default ctor (1)
~T(void) = delete; // default dtor (2)
T(const T&) = delete; // copy ctor (3)
T(const T&&) = delete; // move ctor (4)
T& operator= (const T&) = delete; // copy assignment (5)
T& operator= (const T&&) = delete; // move assignment (6)
Wenn Sie eine dieser 6 verwenden, kommentieren Sie einfach die entsprechende Zeile aus.
Beispiel: Klasse FizzBus benötigt nur dtor und benutzt daher nicht die anderen 5.
// coding standard: disallow when not used
FizzBuzz(void) = delete; // default ctor (1)
// ~FizzBuzz(void); // dtor (2)
FizzBuzz(const FizzBuzz&) = delete; // copy ctor (3)
FizzBuzz& operator= (const FizzBuzz&) = delete; // copy assig (4)
FizzBuzz(const FizzBuzz&&) = delete; // move ctor (5)
FizzBuzz& operator= (const FizzBuzz&&) = delete; // move assign (6)
Wir kommentieren hier nur 1 aus und installieren die Implementierung woanders (wahrscheinlich dort, wo es der Kodierungsstandard vorschlägt). Die anderen 5 (von 6) sind mit delete nicht erlaubt.
Sie können auch '= delete' verwenden, um implizite Werbeaktionen mit Werten unterschiedlicher Größe zu verbieten ... Beispiel
// disallow implicit promotions
template <class T> operator T(void) = delete;
template <class T> Vuint64& operator= (const T) = delete;
template <class T> Vuint64& operator|= (const T) = delete;
template <class T> Vuint64& operator&= (const T) = delete;
Neuer C++ 0x Standard. Siehe Abschnitt 8.4.3 im N3242-Arbeitsentwurf
(Nachtrag zu vorhandenen Antworten)
... und eine gelöschte Funktion soll die erste Deklaration der Funktion sein (mit Ausnahme des Löschens expliziter Spezialisierungen von Funktionsschablonen - das Löschen sollte bei der ersten Deklaration der Spezialisierung erfolgen), dh Sie können eine Funktion nicht deklarieren und später löschen, sagen wir bei seiner Definition lokal zu einer Übersetzungseinheit.
Zitieren [dcl.fct.def.delete]/4 :
Eine gelöschte Funktion ist implizit inline. ( Hinweis: Die Ein-Definition-Regel ( [basic.def.odr] ) gilt für gelöschte Definitionen. - Endnote] Eine gelöschte Definition einer Funktion ist die erste Deklaration der Funktion oder bei einer expliziten Spezialisierung einer Funktionsvorlage die erste Deklaration dieser Spezialisierung. [Beispiel:
struct sometype { sometype(); }; sometype::sometype() = delete; // ill-formed; not first declaration
- Beispiel beenden)
Obwohl eine allgemeine Faustregel lautet: m die Spezialisierung von Funktionsschablonen zu vermeiden da Spezialisierungen nicht am ersten Schritt der Überlastungslösung beteiligt sind, gibt es wohl einige Kontexte, in denen dies nützlich sein kann. Z.B. bei Verwendung einer nicht überladenen primären Funktionsvorlage ohne Definition für alle Typen, die nicht implizit in eine ansonsten konvertierungsbedingte Überladung konvertiert werden sollen; implizites Entfernen einer Anzahl impliziter Konvertierungsübereinstimmungen durch nur Implementieren exakter Typübereinstimmungen in der expliziten Spezialisierung der nicht definierten, nicht überlasteten Primärfunktionsschablone.
Vor dem Konzept der gelöschten Funktion von C++ 11 konnte man dies tun, indem man einfach die Definition der primären Funktionsvorlage wegließ. Dies ergab jedoch obskure undefinierte Referenz Fehler, die möglicherweise keinerlei semantische Absicht gaben der Autor der primären Funktionsvorlage (absichtlich weggelassen?). Wenn wir stattdessen die primäre Funktionsvorlage explizit löschen, werden die Fehlermeldungen für den Fall, dass keine geeignete explizite Spezialisierung gefunden wird, viel netter und zeigen auch, dass das Auslassen/Löschen der Definition der primären Funktionsvorlage beabsichtigt war.
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t);
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
//use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}
Anstatt jedoch einfach eine Definition für die primäre Funktionsvorlage oben wegzulassen und einen unklaren undefinierten Referenzfehler zu erhalten, wenn keine explizite Spezialisierung zutrifft, kann die primäre Vorlagendefinition gelöscht werden:
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t) = delete;
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
use_only_explicit_specializations(str);
/* error: call to deleted function 'use_only_explicit_specializations'
note: candidate function [with T = std::__1::basic_string<char>] has
been explicitly deleted
void use_only_explicit_specializations(T t) = delete; */
}
Es wird eine besser lesbare Fehlermeldung ausgegeben, bei der die Löschabsicht ebenfalls klar erkennbar ist (wobei ein undefinierter Verweis Fehler dazu führen kann, dass der Entwickler dies für einen unüberlegten Fehler hält).
Zurück zu warum sollten wir diese Technik jemals anwenden wollen? Auch hier können explizite Spezialisierungen hilfreich sein, um implizit implizite Konvertierungen zu entfernen.
#include <cstdint>
#include <iostream>
void warning_at_best(int8_t num) {
std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}
template< typename T >
void only_for_signed(T t) = delete;
template<>
void only_for_signed<int8_t>(int8_t t) {
std::cout << "UB safe! 1 byte, " << +t << "\n";
}
template<>
void only_for_signed<int16_t>(int16_t t) {
std::cout << "UB safe! 2 bytes, " << +t << "\n";
}
int main()
{
const int8_t a = 42;
const uint8_t b = 255U;
const int16_t c = 255;
const float d = 200.F;
warning_at_best(a); // 42
warning_at_best(b); // implementation-defined behaviour, no diagnostic required
warning_at_best(c); // narrowing, -Wconstant-conversion warning
warning_at_best(d); // undefined behaviour!
only_for_signed(a);
only_for_signed(c);
//only_for_signed(b);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = unsigned char]
has been explicitly deleted
void only_for_signed(T t) = delete; */
//only_for_signed(d);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = float]
has been explicitly deleted
void only_for_signed(T t) = delete; */
}
Dies ist neu in C++ 0x-Standards, in denen Sie eine geerbte Funktion löschen können.