C++-compilerfout C2280 “probeert te verwijzen naar een verwijderde functie” in Visual Studio 2013 en 2015

Dit fragment is foutloos gecompileerd in Visual Studio 2013 (versie 12.0.31101.00 Update 4)

class A
{
public:
   A(){}
   A(A &&){}
};
int main(int, char*)
{
   A a;
   new A(a);
   return 0;
}

terwijl het is gecompileerd met deze fout in Visual Studio 2015 RC (versie 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 ==========

Ik denk dat de compiler die bij Visual Studio 2015 is geleverd de Copy Constructor genereert en deze markeert als =deleteen dus krijg ik de fout C2280 (die ik trouwens niet kan vinden gedocumenteerd op msdn .microsoft.com).

Laten we zeggen dat ik een codebase heb die kan worden gecompileerd met Visual Studio 2013 (en het werkt omdat het afhankelijk is van de code die automatisch door de compiler wordt gegenereerd) maar niet kan worden gecompileerd met Visual Studio 2015 vanwege C2280. Hoe kan ik de probleem?

Ik dacht eraan om klasse Aop deze manier te declareren:

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

mis ik iets?


Antwoord 1, autoriteit 100%

Van [class.copy]/7, benadruk de mijne:

Als de klassedefinitie niet expliciet een kopie-constructor declareert, wordt impliciet een niet-expliciete gedeclareerd.
Als de klassedefinitie een move-constructor of move-toewijzingsoperator declareert, wordt de impliciet gedeclareerde kopie
constructor is gedefinieerd als verwijderd
; anders wordt het gedefinieerd als standaard (8.4). Het laatste geval wordt afgekeurd als
de klas heeft een door de gebruiker opgegeven operator voor kopieertoewijzing of een door de gebruiker opgegeven destructor.

Er is een gelijkwaardige sectie met vergelijkbare bewoordingen voor kopieeropdracht in paragraaf 18. Dus uw klas is echt:

class A
{
public:
   // explicit
   A(){}
   A(A &&){}
   // implicit
   A(const A&) = delete;
   A& operator=(const A&) = delete;
};

daarom kun je het niet kopiëren. Als u een verplaatsingsconstructor/toewijzing opgeeft en u wilt nog steeds dat de klasse kopieerbaar is, moet u expliciet die speciale lidfuncties opgeven:

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

U moet ook een operator voor verplaatsingstoewijzing declareren. Als je echt behoefte hebt aan deze speciale functies, heb je waarschijnlijk ook de destructor nodig. Zie Regel van Vijf.


Antwoord 2, autoriteit 52%

Ik had hetzelfde probleem en het was te wijten aan een slecht gedefinieerde lidvariabele:

double const deltaBase = .001;

Als u dit invoert, wordt de kopieerconstructor verwijderd. Verwijder de “const” en wijs deze toe in de constructor.


Antwoord 3, autoriteit 7%

Als u een door de gebruiker gedefinieerde verplichtingstructeur voor uw klas schrijft, wordt de kopieerconstructeur verwijderd. Dit is omdat als een klasse speciaal gedrag nodig heeft voor zijn zet-constructor, het waarschijnlijk een soortgelijk gedrag in zijn kopieerconstructeur nodig heeft, zodat de kopieerconstructeur wordt verwijderd om u niet per ongeluk te stoppen met het gebruik van het standaardgedrag.

Als u uw eigen zet Constructor en wilt definiëren, gebruikt u de standaardkopieconstructeur, moet u het als defaultdeclareren, zoals u voorgesteld in uw vraag:

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

Merk op dat als u een aangepaste zetaansluiting definieert, u ook moet nadenken over uw opdrachtoperators en destructor.


Antwoord 4, Autoriteit 7%

Ik zat vast met deze fout, zelfs na “Standaard” de kopie COR. Uitgeblazen, een van mijn Class-lid (Rapidjson’s Document Object) was het kopiëren van kopiëren. Gewijzigd in een referentie, geïnitialiseerd via een * (nieuw Rapidjson :: Document ()) in de initializerlijst van de standaard COR. Het lijkt erop dat alle individuele leden ook worden gekopieerd in aanvulling op de standaardkopie-COR.


Antwoord 5, Autoriteit 5%

Ik liep in een vergelijkbare situatie waarin ik een hiërarchie van klassen had en een destructor in de basisklasse werd virtueel verklaard. In dit geval genereert Compiler niet automatisch verhuis- en kopieerconstructeurs. Dus we moeten deze standaard voor de compiler om de definities voor deze methoden te genereren.

Ik kwam echter een ander probleem tegen nadat ik de constructor voor kopiëren en verplaatsen in gebreke had gesteld. Ik zag dat de compiler nog steeds niet in staat was om constructors voor kopiëren en verplaatsen te genereren. De reden was het gebruik van std::atomic lidvariabele in de basisklasse. Omdat atomaire variabelen niet kopieerbaar of verplaatsbaar zijn, kon de compiler geen definities genereren voor de kopieerconstructor. Hier kreeg ik veel hoofdpijn van en ik moest het probleem op een andere manier oplossen.
Bekijk andere geweldige antwoorden voor een soortgelijk probleem waarmee ik werd geconfronteerd.

Referenties:
Voorkomt een standaard virtuele destructor door de compiler gegenereerde verplaatsingsbewerkingen?

Fout met kopie-constructor/ toewijzingsoperator voor een klasse die std::atomic lidvariabele heeft


Antwoord 6, autoriteit 2%

Ik kwam dezelfde fout tegen, alleen omdat ik std::unique_ptr had misbruikt.

Merk op dat std::unique_ptr niet-kopieerbaaris, het is alleen verplaatsbaar.

Hier is de verkeerde demonstratie.

class word;
class sentence
{
    public:
        sentence();
        ~sentence();
    public:
        // Wrong demonstration, because I pass the parameter by value/copying
        // I should use 'std::shared_ptr< word >' instead.
        sentence(std::initializer_list< std::unique_ptr< word > > sentence);
};

De volgende code is afkomstig uit de STL-bibliotheek van de MSVC-compiler. We kunnen zien dat de kopieerconstructor en de kopieertoewijzingsoperator van klasse unique_ptr expliciet verwijderdzijn.

   unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

Antwoord 7

Ik heb vandaag geconfronteerd met dit probleem en de mijne werd veroorzaakt door zowel std::stringstreamen std::ostreamals ledenvariabelen. Ik dacht dat dit in eerste instantie werd veroorzaakt omdat ik per ongeluk een van hen heb genoemd als sstreamdie de naam voor het headerbestand was <sstreamn>ik had eerder opgenomen.

Maar het wijzigen van de naam hielp niet, en ik moest de ostreamVariabele volledig hiervoor verwijderen om weer te werken! Toen besefte ik dat ik het zo verkeerd had verklaard:

std::ostream some_stream;

Hoewel het had moeten zijn:

...
std::ostream some_stream(&filebuf);

In principe was ik veel beter af met ofstreamin plaats daarvan!

Other episodes