web-dev-qa-db-fra.com

Erreur C2280 du compilateur C ++ "tentative de référence à une fonction supprimée" dans Visual Studio 2013 et 2015

Cet extrait de code est compilé sans erreurs dans Visual Studio 2013 (version 12.0.31101.00 Update 4)

class A
{
public:
   A(){}
   A(A &&){}
};

int main(int, char*)
{
   A a;
   new A(a);
   return 0;
}

alors qu'il est compilé avec cette erreur dans Visual Studio 2015 RC (version 14.0.22823.1 D14REL):

1>------ Build started: Project: foo, Configuration: Debug Win32 ------
1>  foo.cpp
1>c:\dev\foo\foo.cpp(11): error C2280: 'A::A(const A &)': attempting to reference a deleted function
1>  c:\dev\foo\foo.cpp(6): note: compiler has generated 'A::A' here
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Je pense que le compilateur livré avec Visual Studio 2015 génère le constructeur de copie et le marque comme =delete et j'obtiens donc l'erreur C2280 (que je ne trouve d'ailleurs pas documentée sur msdn.Microsoft.com).

Supposons maintenant que j'ai une base de code compilable avec Visual Studio 2013 (et que cela fonctionne car il s'appuie sur le code généré automatiquement par le compilateur), mais pas avec Visual Studio 2015 en raison de C2280, comment puis-je résoudre le problème?

Je pensais déclarer la classe A de cette façon:

class A
{
public:
   A(){}
   A(A &&){}
   A(const A&)=default;
};

est-ce que je manque quelque chose?

26

De [class.copy]/7, c'est moi qui souligne:

Si la définition de classe ne déclare pas explicitement un constructeur de copie, un autre non explicite est déclaré implicitement. Si la définition de classe déclare un constructeur de déplacement ou un opérateur d'affectation de déplacement, le constructeur de copie implicitement déclaré est défini comme étant supprimé ; sinon, il est défini par défaut (8.4). Ce dernier cas est déconseillé si la classe dispose d'un opérateur d'affectation de copie déclaré par l'utilisateur ou d'un destructeur déclaré par l'utilisateur.

Il y a une section équivalente avec un libellé similaire pour l'affectation de copie au paragraphe 18. Votre classe est donc vraiment:

class A
{
public:
   // explicit
   A(){}
   A(A &&){}

   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

c'est pourquoi vous ne pouvez pas le copier-construire. Si vous fournissez un constructeur/une assignation de déplacement et que vous souhaitez toujours que la classe puisse être copiée, vous devrez explicitement fournir ces fonctions membres spéciales:

    A(const A&) = default;
    A& operator=(const A&) = default;

Vous devrez également déclarer un opérateur d’affectation de déménagement. Si vous avez vraiment besoin de ces fonctions spéciales, vous aurez probablement aussi besoin du destructeur. Voir règle de cinq .

37
Barry

J'ai eu le même problème et cela était dû à une variable membre mal définie:

double const deltaBase = .001;

En mettant ceci dans, le constructeur de copie sera supprimé. Débarrassez-vous du "const" et attribuez-le au constructeur.

22
doby

Si vous écrivez un constructeur de déplacement défini par l'utilisateur pour votre classe, le constructeur de copie sera supprimé. En effet, si une classe a besoin d'un comportement spécial pour son constructeur de déplacement, elle a probablement besoin d'un comportement similaire dans son constructeur de copie. Le constructeur de copie sera donc supprimé pour vous empêcher d'utiliser par inadvertance le comportement par défaut.

Si vous voulez définir votre propre constructeur de déplacements and utilisez le constructeur de copie par défaut, vous devez le déclarer comme default, comme vous l'avez suggéré dans votre question:

class A
{
public:
   A(){}
   A(A &&){}
   //I know what I'm doing, compiler, use the default version.
   A(const A&)=default;
};

Notez que si vous définissez un constructeur de déplacement personnalisé, vous devez également tenir compte de vos opérateurs d'attribution et de votre destructeur.

3
TartanLlama

J'étais coincé avec cette erreur même après "défaut" le copieur de copie. En fin de compte, un membre de mon groupe (objet Document de rapidjson) refusait la copie. Changé en une référence, initialisée via un * (new rapidjson :: Document ()) dans la liste des initialiseurs du ctor par défaut. On dirait que tous les membres individuels doivent également pouvoir être copiés en plus du copieur par défaut.

0
n-mam