class my_class
{
...
my_class(my_class const &) = delete;
...
};
Was macht = delete
meinst du in diesem zusammenhang?
Gibt es noch andere “Modifikatoren” (außer = 0
und = delete
)?
Pat O’Keefe
class my_class
{
...
my_class(my_class const &) = delete;
...
};
Was macht = delete
meinst du in diesem zusammenhang?
Gibt es noch andere “Modifikatoren” (außer = 0
und = delete
)?
Prasun Saurav
Das Löschen einer Funktion ist eine C++11-Funktion:
Die gängige Redewendung vom „Kopierverbot“ lässt sich nun direkt ausdrücken:
class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
[…]
Der “Lösch”-Mechanismus kann für jede Funktion verwendet werden. Beispielsweise können wir eine unerwünschte Konvertierung wie folgt eliminieren:
struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less };
Ist die herkömmliche Methode zum „Kopieren verbieten“ nicht einfach, den copy-ctor und operator= „privat“ zu machen? Dieser geht noch etwas weiter und weist den Compiler an, die Funktionen gar nicht erst zu generieren. Wenn sie sowohl privat als auch =delete sind, ist das Kopieren dann doppelt verboten?
– Reb.Kabine
2. Februar 2017 um 1:50 Uhr
@Reb, =delete
macht die Methode selbst aus Kontexten, die sehen können, unzugänglich private
Methoden (dh innerhalb der Klasse und ihrer Freunde). Dies beseitigt jegliche Unsicherheit beim Lesen des Codes. @Prasoon, dieses zweite Beispiel löscht immer noch nur Konstruktoren – es wäre schön, einen gelöschten zu sehen operator long ()
zum Beispiel.
– Toby Speight
17. August 2017 um 14:34 Uhr
@Reb.Cabin Verwenden = delete
ist besser als benutzen private
oder andere ähnliche Mechanismen, weil Sie normalerweise wollen die verbotene Funktion muss sichtbar deklariert und für die Auflösung von Überlastungen usw. berücksichtigt werden, damit sie so früh wie möglich fehlschlagen und dem Benutzer den klarsten Fehler liefern kann. Jede Lösung, bei der die Deklaration “ausgeblendet” wird, reduziert diesen Effekt.
– Leuschenko
26. Februar 2019 um 16:34 Uhr
Gibt es einen besonderen Grund, den Kopierkonstruktor öffentlich zu machen und das Schlüsselwort delete anzuwenden? Warum nicht den Konstruktor privat lassen und das Schlüsselwort anwenden?
– Dohn Joe
24. Juni 2019 um 8:39 Uhr
Nicht immer. Sie können eine virtuelle Funktion der Basisklasse in abgeleitet nicht löschen.
– Der Philomath
15. Januar 2021 um 6:45 Uhr
mkaes
= 0
bedeutet, dass eine Funktion rein virtuell ist und Sie kein Objekt aus dieser Klasse instanziieren können. Sie müssen davon ableiten und diese Methode implementieren= delete
bedeutet, dass der Compiler diese Konstruktoren nicht für Sie generiert. AFAIK ist dies nur für den Kopierkonstruktor und den Zuweisungsoperator zulässig. Aber ich bin nicht allzu gut im kommenden Standard. Es gibt einige andere Verwendungen von =delete
Syntax. Sie können es beispielsweise verwenden, um implizite Konvertierungen, die mit dem Aufruf stattfinden könnten, ausdrücklich zu verbieten. Dazu löscht man einfach die überladenen Funktionen. Weitere Informationen finden Sie auf der Wikipedia-Seite zu C++0x.
– LiKao
1. April 2011 um 13:59 Uhr
Das mache ich, sobald ich welche finde. Schätzen Sie, es ist an der Zeit, c++0X einzuholen
– mkaes
1. April 2011 um 15:08 Uhr
Ja, C++0x rockt. Ich kann es kaum erwarten, dass GCC 4.5+ häufiger wird, also kann ich anfangen, Lambdas zu verwenden.
– LiKao
1. April 2011 um 15:21 Uhr
Die Beschreibung für = delete
ist nicht ganz richtig. = delete
kann für jede Funktion verwendet werden, in diesem Fall wird es ausdrücklich als gelöscht markiert und jede Verwendung führt zu einem Compilerfehler. Für spezielle Member-Funktionen bedeutet dies insbesondere auch, dass sie dann nicht vom Compiler für Sie generiert werden, sondern das ist nur eine Folge des Löschens, und nicht was = delete
wirklich ist.
– Mikrovirus
4. Oktober 2016 um 9:11 Uhr
Saurav Sahu
Dieser Auszug aus Die Programmiersprache C++ [4th Edition] – Bjarne Stroustrup Buchgespräche über die eigentlicher Zweck hinter der Verwendung =delete
:
3.3.4 Operationen unterdrücken
Die Verwendung des standardmäßigen Kopierens oder Verschiebens für eine Klasse in einer Hierarchie ist normalerweise a Katastrophe: Wenn wir nur einen Zeiger auf eine Basis haben, wissen wir einfach nicht, welche Mitglieder die abgeleitete Klasse hat, also haben wir kann nicht wissen, wie man sie kopiert. Daher ist es normalerweise am besten, die Standardoperationen zum Kopieren und Verschieben zu löschen, d. h. die Standarddefinitionen dieser beiden Operationen zu eliminieren:
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(); // ... };
Jetzt wird ein Versuch, ein Shape zu kopieren, vom Compiler abgefangen.
Das
=delete
Der Mechanismus ist allgemein, das heißt, er kann verwendet werden, um jede Operation zu unterdrücken
Kyle Delaney
Gibt es noch andere “Modifikatoren” (außer
= 0
und= delete
)?
Da anscheinend niemand sonst diese Frage beantwortet hat, sollte ich erwähnen, dass es sie auch gibt =default
.
2785528
Die Codierungsstandards, mit denen ich gearbeitet habe, hatten für die meisten Klassendeklarationen Folgendes.
// 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: Die Klasse FizzBus benötigt nur dtor und verwendet daher die anderen 5 nicht.
// 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 an anderer Stelle (wahrscheinlich dort, wo der Codierungsstandard vorschlägt). Die anderen 5 (von 6) werden mit delete nicht zugelassen.
Sie können auch ‘= delete’ verwenden, um implizite Heraufstufen von Werten unterschiedlicher Größe zu unterbinden … 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;
Das Erstellen eines Objekts einer Klasse mit einem gelöschten Konstruktor ist illegal.
– KeyC0de
23. Oktober 2020 um 20:54 Uhr
@Nikos – Nein – Sie müssen lediglich einen Konstruktor bereitstellen. Das Beispiel des Hinzufügens von ” T() = delete; ” hindert den Compiler daran, einen (minimalen) Standard-Ctor hinzuzufügen, was gelegentlich nützlich ist, aber es Ihnen immer noch erlaubt, einen (vermutlich-macht-etwas-Nützlichen) Ctor hinzuzufügen.
– 2785528
25. Oktober 2020 um 1:07 Uhr
Richard
= delete
ist ein in C++11 eingeführtes Feature. Gem =delete
Es ist nicht erlaubt, diese Funktion aufzurufen.
Im Detail.
Angenommen in einer Klasse.
Class ABC{
Int d;
Public:
ABC& operator= (const ABC& obj) =delete
{
}
};
Beim Aufruf dieser Funktion zur Objektzuweisung ist dies nicht zulässig. Bedeutet, dass der Zuweisungsoperator sich auf das Kopieren von einem Objekt zu einem anderen beschränken wird.
Das Erstellen eines Objekts einer Klasse mit einem gelöschten Konstruktor ist illegal.
– KeyC0de
23. Oktober 2020 um 20:54 Uhr
@Nikos – Nein – Sie müssen lediglich einen Konstruktor bereitstellen. Das Beispiel des Hinzufügens von ” T() = delete; ” hindert den Compiler daran, einen (minimalen) Standard-Ctor hinzuzufügen, was gelegentlich nützlich ist, aber es Ihnen immer noch erlaubt, einen (vermutlich-macht-etwas-Nützlichen) Ctor hinzuzufügen.
– 2785528
25. Oktober 2020 um 1:07 Uhr
(Ergänzung zu bestehenden Antworten)
… Und eine gelöschte Funktion muss die erste Deklaration der Funktion sein (mit Ausnahme des Löschens expliziter Spezialisierungen von Funktionsvorlagen – das Löschen sollte bei der ersten Deklaration der Spezialisierung erfolgen), was bedeutet, dass Sie eine Funktion nicht deklarieren und später löschen können, sagen wir, bei seiner Definition lokal zu einer Übersetzungseinheit.
Zitieren [dcl.fct.def.delete]/4:
Eine gelöschte Funktion ist implizit inline. ( Notiz: Die Ein-Definition-Regel ([basic.def.odr]) gilt für gelöschte Definitionen. — Schlussbemerkung ]Eine gelöschte Definition einer Funktion muss die erste Deklaration der Funktion oder, für eine explizite Spezialisierung einer Funktionsvorlage, die erste Deklaration dieser Spezialisierung sein. [ Example:
struct sometype { sometype(); }; sometype::sometype() = delete; // ill-formed; not first declaration
— end example )
Albeit a general rule of thumb is to avoid specializing function templates as specializations do not participate in the first step of overload resolution, there are arguable some contexts where it can be useful. E.g. when using a non-overloaded primary function template with no definition to match all types which one would not like implicitly converted to an otherwise matching-by-conversion overload; i.e., to implicitly remove a number of implicit-conversion matches by only implementing exact type matches in the explicit specialization of the non-defined, non-overloaded primary function template.
Before the deleted function concept of C++11, one could do this by simply omitting the definition of the primary function template, but this gave obscure undefined reference errors that arguably gave no semantic intent whatsoever from the author of primary function template (intentionally omitted?). If we instead explicitly delete the primary function template, the error messages in case no suitable explicit specialization is found becomes much nicer, and also shows that the omission/deletion of the primary function template’s definition was intentional.
#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< ...
}
However, instead of simply omitting a definition for the primary function template above, yielding an obscure undefined reference error when no explicit specialization matches, the primary template definition can be deleted:
#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>] wurde explizit gelöscht void use_only_explicit_specializations(T t) = delete; */ }
Ergibt eine besser lesbare Fehlermeldung, bei der auch die Löschabsicht deutlich sichtbar ist (wobei eine undefinierte Referenz Fehler könnte dazu führen, dass der Entwickler dies für einen unüberlegten Fehler hält).
Um noch einmal darauf zurückzukommen, warum sollten wir diese Technik jemals verwenden wollen? Auch hier könnten explizite Spezialisierungen sinnvoll sein implizit Entfernen Sie implizite Konvertierungen.
#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; */
}
Ich stehe korrigiert, ich hatte dieses C++0x-Feature übersehen. Ich dachte es wäre ein
#define
a la Qt, das zu 0 ausgewertet und dann eine versteckte Funktion oder so etwas deklariert hat.– Blind
1. April 2011 um 15:13 Uhr
Ich habe eine Erinnerung an ein Schlüsselwort “deaktivieren”, das dasselbe oder etwas Ähnliches bedeutet. Bilde ich es mir ein? Oder gibt es einen feinen Unterschied zwischen ihnen?
– Steward
30. Dezember 2018 um 18:32 Uhr