wake-up-neo.com

C ++ - Compilerfehler C2280 "Versuch, auf eine gelöschte Funktion zu verweisen" in Visual Studio 2013 und 2015

Dieses Snippet wurde in Visual Studio 2013 (Version 12.0.31101.00 Update 4) fehlerfrei kompiliert.

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

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

während es mit diesem Fehler in Visual Studio 2015 RC (Version 14.0.22823.1 D14REL) kompiliert wird:

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 ==========

Ich denke, dass der mit Visual Studio 2015 gelieferte Compiler den Kopierkonstruktor generiert und als =delete Markiert. Daher erhalte ich den Fehler C2280 (den ich übrigens auf msdn.Microsoft.com nicht finden kann).

Angenommen, ich habe eine Codebasis, die mit Visual Studio 2013 kompiliert werden kann (und die funktioniert, weil sie auf dem vom Compiler automatisch generierten Code basiert), aber aufgrund von C2280 nicht mit Visual Studio 2015 kompiliert werden kann. Wie kann ich das Problem beheben?

Ich wollte die Klasse A folgendermaßen deklarieren:

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

vermisse ich etwas?

26

Aus [class.copy]/7, Hervorhebung meiner:

Wenn die Klassendefinition einen Kopierkonstruktor nicht explizit deklariert, wird ein nicht expliziter Konstruktor implizit deklariert. Wenn die Klassendefinition einen Verschiebekonstruktor oder einen Verschiebezuweisungsoperator deklariert, wird der implizit deklarierte Kopierkonstruktor als gelöscht definiert ; Andernfalls wird es als Standard definiert (8.4). Der letztere Fall ist veraltet, wenn die Klasse einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor hat.

In Paragraph 18 gibt es einen entsprechenden Abschnitt mit ähnlichem Wortlaut für die Zuweisung von Kopien. Ihre Klasse ist also wirklich:

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

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

aus diesem Grund können Sie es nicht kopieren. Wenn Sie einen Verschiebungskonstruktor/eine Verschiebungszuweisung angeben und die Klasse weiterhin kopierbar sein soll, müssen Sie die folgenden speziellen Elementfunktionen explizit bereitstellen:

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

Sie müssen auch einen Verschiebungszuweisungsoperator deklarieren. Wenn Sie diese speziellen Funktionen wirklich benötigen, benötigen Sie wahrscheinlich auch den Destruktor. Siehe Regel von fünf .

37
Barry

Ich hatte das gleiche Problem und es lag an einer schlecht definierten Mitgliedsvariablen:

double const deltaBase = .001;

Wenn Sie dies eingeben, wird der Kopierkonstruktor gelöscht. Werde die "const" los und weise sie im Konstruktor zu.

22
doby

Wenn Sie einen benutzerdefinierten Verschiebungskonstruktor für Ihre Klasse schreiben, wird der Kopierkonstruktor gelöscht. Dies liegt daran, dass eine Klasse, die ein spezielles Verhalten für ihren Verschiebungskonstruktor benötigt, wahrscheinlich ein ähnliches Verhalten in ihrem Kopierkonstruktor benötigt, sodass der Kopierkonstruktor gelöscht wird, um zu verhindern, dass Sie versehentlich das Standardverhalten verwenden.

Wenn Sie Ihren eigenen Verschiebungskonstruktor definieren möchten nd verwenden Sie den Standard-Kopierkonstruktor, müssen Sie ihn wie in Ihrer Frage vorgeschlagen als default deklarieren:

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

Beachten Sie, dass Sie beim Definieren eines benutzerdefinierten Verschiebungskonstruktors auch Ihre Zuweisungsoperatoren und Destruktoren berücksichtigen sollten.

3
TartanLlama

Ich war mit diesem Fehler auch nach "Standard" der Kopie ctor stecken. Es stellte sich heraus, dass einer meiner Klassenkameraden (rapidjsons Dokumentobjekt) das Kopieren untersagte. Es wurde in eine Referenz geändert, die über ein * (new rapidjson :: Document ()) in der Initialisierungsliste des Standard-Ctors initialisiert wurde. Es sieht so aus, als ob alle einzelnen Mitglieder zusätzlich zum voreingestellten Kopier-Ctor auch kopierbar sein sollten.

0
n-mam