Bedeutung von = nach Funktionsdeklaration löschen

Lesezeit: 10 Minuten

Benutzer-Avatar
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)?

  • 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

Benutzer-Avatar
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

Benutzer-Avatar
mkaes

  1. = 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
  2. = 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


Benutzer-Avatar
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

Benutzer-Avatar
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.

https://docs.microsoft.com/en-us/cpp/cpp/explicitly-defaulted-and-deleted-functions#explicitly-defaulted-functions

Benutzer-Avatar
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


Benutzer-Avatar
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


Eine gelöschte Funktion ist implizit inline

(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 )

A primary function template with a deleted definition can be specialized

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; */
}

1013230cookie-checkBedeutung von = nach Funktionsdeklaration löschen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy