Fehler: Verwendung der gelöschten Funktion

121

Ich habe an einem C ++ - Code gearbeitet, den ein Freund geschrieben hat, und erhalte den folgenden Fehler, den ich beim Kompilieren mit gcc4.6 noch nie gesehen habe:

error: use of deleted function

GameFSM_<std::array<C, 2ul> >::hdealt::hdealt()’ is implicitly deleted because the default definition would be ill-formed:
uninitialized non-static const member const h_t FlopPokerGameFSM_<std::array<C, 2ul> >::hdealt::h

Bearbeiten: Dies kommt aus einem Teil des Codes mit Boost MSM: Boost Webpage

Edit2: Es wird = delete()nirgendwo im Quellcode verwendet.

Was bedeutet dieser Fehler im Allgemeinen? Worauf sollte ich achten, wenn diese Art von Fehler auftritt?

Shuttle87
quelle
4
und den Code, den Sie kompilieren?
ColWhi
Ich habe mich nur gefragt, was der Fehler bedeutet. Muss ich den Code auch dafür posten?
Shuttle87
1
gcc.gnu.org/bugzilla/show_bug.cgi?id=47417 könnte helfen, verwenden Sie auch Boost?
ColWhi
@ Sasquiha, ja ich benutze Boost MSM.
Shuttle87
20
Da dies die erste Google-Übereinstimmung für diese Art von Fehler ist - hier nicht der Fall, aber die häufigste Ursache für diese Art von Fehler ist, nachdem Sie einer Klasse einen benutzerdefinierten Konstruktor hinzugefügt haben -, stellt der Compiler die Erstellung des Standardkonstruktors ein Wenn eine Instanz der Klasse jemals über den Standardkonstruktor erstellt wird, wird dieser Fehler angezeigt. Fügen Sie einfach den Standardkonstruktor explizit hinzu.
SF.

Antworten:

170

Die Fehlermeldung besagt eindeutig, dass der Standardkonstruktor implizit gelöscht wurde . Es heißt sogar, warum: Die Klasse enthält eine nicht statische const-Variable, die vom Standard-ctor nicht initialisiert würde.

class X {
    const int x;
};

Da dies der Fall X::xist const, muss es initialisiert werden - aber ein Standard-Ctor würde es normalerweise nicht initialisieren (da es sich um einen POD-Typ handelt). Um einen Standard-Ctor zu erhalten, müssen Sie daher selbst einen definieren (und dieser muss initialisiert werden x). Sie können die gleiche Situation mit einem Mitglied haben, das eine Referenz ist:

class X { 
    whatever &x;
};

Es ist wahrscheinlich erwähnenswert, dass beide auch die implizite Erstellung eines Zuweisungsoperators aus im Wesentlichen demselben Grund deaktivieren. Der implizite Zuweisungsoperator führt normalerweise eine mitgliederweise Zuweisung durch, aber mit einem const-Mitglied oder Referenzmitglied kann er dies nicht tun, da das Mitglied nicht zugewiesen werden kann. Damit die Zuweisung funktioniert, müssen Sie Ihren eigenen Zuweisungsoperator schreiben.

Aus diesem Grund sollte ein constMitglied normalerweise statisch sein. Wenn Sie eine Zuweisung vornehmen, können Sie das const-Mitglied ohnehin nicht zuweisen. In einem typischen Fall haben alle Ihre Instanzen denselben Wert, sodass sie auch den Zugriff auf eine einzelne Variable gemeinsam nutzen können, anstatt viele Kopien einer Variablen zu haben, die alle denselben Wert haben.

Es ist natürlich möglich, Instanzen mit unterschiedlichen Werten zu erstellen. Sie übergeben (zum Beispiel) beim Erstellen des Objekts einen Wert, sodass zwei verschiedene Objekte zwei unterschiedliche Werte haben können. Wenn Sie jedoch versuchen, sie auszutauschen, behält das const-Element seinen ursprünglichen Wert bei, anstatt ausgetauscht zu werden.

Jerry Sarg
quelle
@ Jeffrey Coffin: Die eigentliche Fehlermeldung wurde als Bearbeitung veröffentlicht. Die erste Fehlermeldung wurde nur veröffentlichtC++ error: use of deleted function
Alok Save
1
@Als: Entschuldigung, ich hätte wahrscheinlich ausdrücklich sagen sollen, dass ich das nicht als Beleidigung oder irgendetwas in dieser Reihenfolge beabsichtigt habe, nur dass das, was derzeit verfügbar war, deutlich machte, dass diese Antworten nicht richtig waren.
Jerry Coffin
Keine Probleme, ich wollte nicht unnachgiebig sein ... Ihre Antwort ist fantastisch und erklärt die Situation am besten. +1 von mir :)
Alok Save
Ich gehe
Saher Ahwal
2
@ OllieFord: Das hängt davon ab. Was soll passieren, wenn Sie (zum Beispiel) ein Objekt mit einem Wert in diesem Feld einem anderen Objekt zuweisen, das in diesem Feld einen anderen Wert hat? Wenn es überschrieben werden soll, kann es nicht const sein. Wenn dies überhaupt nicht zulässig sein sollte, ist der Wert möglicherweise tatsächlich Teil des Typs (z. B. ein Vorlagenparameter, falls er zur Kompilierungszeit bekannt ist).
Jerry Coffin
11

Sie verwenden eine Funktion, die als gekennzeichnet ist deleted.
Z.B:

int doSomething( int ) = delete;

Das = Löschen ist eine neue Funktion von C ++ 0x. Dies bedeutet, dass der Compiler die Kompilierung sofort beenden und sich beschweren sollte, dass diese Funktion gelöscht wurde, sobald der Benutzer diese Funktion verwendet.

Wenn Sie diesen Fehler sehen, sollten Sie die Funktionsdeklaration auf überprüfen =delete.

Um mehr über diese neue Funktion in C ++ 0x eingeführt, überprüfen Sie diese aus.

Alok Speichern
quelle
7
Wann wäre es aus Neugier hilfreich, so etwas zu tun?
Pepe
@Peter: um implizite Konvertierungen zu verhindern.
R. Martinho Fernandes
7
Tatsächlich heißt es "implizit gelöscht, weil ..." , das obige Beispiel wäre explizit.
Georg Fritzsche
@ Peter R: sieht so aus, als wäre dies ein Beispiel: en.wikipedia.org/wiki/…
Shuttle87
1
@ Downvoter: Die eigentliche Fehlermeldung wurde als Bearbeitung gepostet. Die anfängliche Fehlermeldung war nurC++ error: use of deleted function
Alok Save
4

gcc 4.6 unterstützt eine neue Funktion gelöschter Funktionen, in die Sie schreiben können

hdealt() = delete;

um den Standardkonstruktor zu deaktivieren.

Hier hat der Compiler offensichtlich gesehen, dass ein Standardkonstruktor nicht generiert werden kann, und =deletedas für Sie.

Bo Persson
quelle
2

Ich bin auf diesen Fehler gestoßen, als ich von einer abstrakten Klasse geerbt und nicht alle reinen virtuellen Methoden in meiner Unterklasse implementiert habe.

Christopher
quelle
1
In ähnlicher Weise habe ich dasselbe erhalten, indem ich public virtualvon einer Basisklasse der 2. Ebene abgeleitet habe, in der die Basisklasse der 1. Ebene einen explizit gelöschten Standardkonstruktor hatte. Durch das Entfernen wurde virtualdas Problem behoben, ohne dass alle Methoden implementiert werden mussten.
Maitre Bart
1

Im aktuellen C ++ 0x-Standard können Sie Standardkonstruktoren mit der Löschsyntax explizit deaktivieren, z

MyClass() = delete;

Gcc 4.6 ist die erste Version, die diese Syntax unterstützt. Vielleicht ist das das Problem ...

jarmond
quelle
Gcc 4.6 is the first version to support this syntaxIch denke, das würde erklären, warum ich es noch nie gesehen habe, da ich gerade erst angefangen habe, gcc4.6 zu verwenden.
Shuttle87
2
Ich verwende diese Syntax seit Jahren mit GCC 4.5. Ich meine Tage.
R. Martinho Fernandes
Ah, ich muss an delegierte Ctors gedacht haben, die in GCC 4.6 enthalten sind.
Jarmond
1

Der Wechsel von gcc 4.6 zu gcc 4.8 hat dies für mich gelöst.

Michael Bosworth
quelle