erreur: utilisation de la fonction supprimée

122

J'ai travaillé sur du code C ++ qu'un ami a écrit et j'obtiens l'erreur suivante que je n'ai jamais vue auparavant lors de la compilation avec gcc4.6:

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

Edit: Cela provient d'une partie du code utilisant boost MSM: Boost Webpage

Edit2: Il n'est = delete()utilisé nulle part dans le code source.

De manière générale, que signifie cette erreur? Que dois-je rechercher lorsque ce type d'erreur se produit?

navette87
la source
4
et le code que vous compilez?
ColWhi
Je me demandais plus simplement ce que signifiait l'erreur? Dois-je également publier le code pour cela?
navette87
1
gcc.gnu.org/bugzilla/show_bug.cgi?id=47417 pourrait vous aider, utilisez-vous également boost?
ColWhi
@Sasquiha, oui j'utilise boost MSM.
navette87
20
Comme cela apparaît comme la première correspondance Google pour ce type d'erreur - pas le cas ici, mais la cause la plus courante de ce type d'erreur est après que vous ayez ajouté un constructeur personnalisé à une classe - le compilateur cesse de créer le constructeur par défaut , et si une instance de la classe est déjà créée via le constructeur par défaut, cette erreur apparaît. Ajoutez simplement le constructeur par défaut explicitement.
SF.

Réponses:

171

Le message d'erreur indique clairement que le constructeur par défaut a été supprimé implicitement . Il dit même pourquoi: la classe contient une variable const non statique, qui ne serait pas initialisée par le ctor par défaut.

class X {
    const int x;
};

Depuis X::xest const, il doit être initialisé - mais cteur par défaut n'initialise pas normalement (car il est un type POD). Par conséquent, pour obtenir un cteur par défaut, vous devez en définir un vous-même (et il doit s'initialiser x). Vous pouvez avoir le même genre de situation avec un membre qui est une référence:

class X { 
    whatever &x;
};

Il est probablement intéressant de noter que ces deux éléments désactiveront également la création implicite d'un opérateur d'affectation, pour essentiellement la même raison. L'opérateur d'affectation implicite effectue normalement une affectation par membre, mais avec un membre const ou un membre de référence, il ne peut pas le faire car le membre ne peut pas être affecté. Pour que l'affectation fonctionne, vous devez écrire votre propre opérateur d'affectation.

C'est pourquoi un constmembre doit généralement être statique - lorsque vous effectuez une affectation, vous ne pouvez pas attribuer le membre const de toute façon. Dans un cas typique, toutes vos instances auront la même valeur, donc elles pourraient aussi bien partager l'accès à une seule variable au lieu d'avoir de nombreuses copies d'une variable qui auront toutes la même valeur.

Il est bien sûr possible de créer des instances avec des valeurs différentes - vous (par exemple) transmettez une valeur lorsque vous créez l'objet, donc deux objets différents peuvent avoir deux valeurs différentes. Si, cependant, vous essayez de faire quelque chose comme les permuter, le membre const conservera sa valeur d'origine au lieu d'être permuté.

Jerry Coffin
la source
@Jeffry Coffin: Le message d'erreur réel a été publié en tant que modification, le message d'erreur initial publié était uniquementC++ error: use of deleted function
Alok Save
1
@Als: Désolé, j'aurais probablement dû être explicite que je n'avais pas l'intention que cela soit une insulte ou quoi que ce soit dans cet ordre, juste que ce qui était actuellement disponible faisait apparaître que ces réponses n'étaient pas correctes.
Jerry Coffin
Pas de problème, je ne voulais pas être catégorique ... Votre réponse est fantastique et explique le mieux la situation. +1 de moi :)
Alok Save
Je suppose que vous pourrez peut-être m'aider avec mon problème ici s'il vous plaît: stackoverflow.com/questions/23349524/...
Saher Ahwal
2
@OllieFord: Cela dépend. Que se passe-t-il si (par exemple) vous attribuez un objet avec une valeur dans ce champ à un autre qui a une valeur différente dans ce champ? S'il doit être écrasé, il ne peut pas être const. Si cela ne doit pas du tout être autorisé, alors la valeur peut vraiment faire partie du type (par exemple, un paramètre de modèle, s'il est connu au moment de la compilation).
Jerry Coffin
11

Vous utilisez une fonction marquée comme deleted.
Par exemple:

int doSomething( int ) = delete;

Le = delete est une nouvelle fonctionnalité de C ++ 0x. Cela signifie que le compilateur doit immédiatement arrêter la compilation et se plaindre "cette fonction est supprimée" une fois que l'utilisateur utilise cette fonction.

Si vous voyez cette erreur, vous devez vérifier la déclaration de fonction pour =delete.

Pour en savoir plus sur cette nouvelle fonctionnalité introduite dans C ++ 0x, consultez ceci .

Alok Save
la source
7
Par curiosité, quand faire quelque chose comme ça serait utile?
Pepe
@Peter: pour éviter les conversions implicites.
R. Martinho Fernandes
7
En fait, il est dit "supprimé implicitement parce que ..." , l'exemple ci-dessus serait explicite.
Georg Fritzsche
@Peter R: ressemble à ceci est un exemple: en.wikipedia.org/wiki/…
navette87
1
@Downvoter: Le message d'erreur réel a été publié en tant que modification, le message d'erreur initial publié était uniquementC++ error: use of deleted function
Alok Save
4

gcc 4.6 prend en charge une nouvelle fonctionnalité de fonctions supprimées, où vous pouvez écrire

hdealt() = delete;

pour désactiver le constructeur par défaut.

Ici, le compilateur a évidemment vu qu'un constructeur par défaut ne peut pas être généré, et =deletefaites-le pour vous.

Bo Persson
la source
2

J'ai rencontré cette erreur en héritant d'une classe abstraite et en n'implémentant pas toutes les méthodes virtuelles pures dans ma sous-classe.

Christophe
la source
1
De même, j'ai obtenu la même chose en dérivant public virtuald'une classe de base de deuxième niveau où la classe de base de premier niveau avait un constructeur par défaut explicitement supprimé. La suppression a virtualrésolu le problème sans avoir à implémenter toutes les méthodes.
Maitre Bart le
1

Dans la norme actuelle C ++ 0x, vous pouvez désactiver explicitement les constructeurs par défaut avec la syntaxe de suppression, par exemple

MyClass() = delete;

Gcc 4.6 est la première version à prendre en charge cette syntaxe, c'est peut-être là le problème ...

jarmond
la source
Gcc 4.6 is the first version to support this syntaxJe suppose que cela expliquerait pourquoi je ne l'ai jamais vu auparavant car je viens de commencer à utiliser gcc4.6 récemment.
navette87
2
J'utilise cette syntaxe avec GCC 4.5 depuis des années. Je veux dire des jours.
R. Martinho Fernandes
Ah, j'ai dû penser aux cteurs délégués qui sont dans GCC 4.6.
jarmond
1

Le passage de gcc 4.6 à gcc 4.8 a résolu ce problème pour moi.

Michael Bosworth
la source