2015-07-07 40 views
16

Dieser Code-Schnipsel ohne Fehler in Visual Studio 2013 (Version 12.0.31101.00 Update 4) kompiliert wirdC++ Compiler Error C2280 "versucht, eine gelöschte Funktion zu verweisen" in Visual Studio 2013 und 2015

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

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

während Kompilierungsstatus mit diesem Fehler in 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 ========== 

ich denke, dass der Compiler mit Visual Studio ausgeliefert 2015 den Copy-Konstruktor erzeugt und markiert sie als =delete und so bekomme ich den Fehler C2280 (was ich übrigens nicht dokumentiert finden kann auf msdn.microsoft.com).

Jetzt sagen wir, ich habe eine Codebasis, die mit Visual Studio 2013 kompilierbar ist (und es funktioniert, weil es auf dem vom Compiler automatisch generierten Code beruht), aber nicht mit Visual Studio 2015 aufgrund von C2280 kompilierbar, wie kann ich beheben das Problem?

Ich dachte Klasse zu erklären A auf diese Weise:

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

bin ich etwas fehlt?

+1

Zusammen mit dem 'A & operator = (A &&) ;' und 'A & operator = (const A &);' – Jagannath

Antwort

23

Von [class.copy]/7, Hervorhebung von mir:

Wenn die Klassendefinition nicht explizit eine Kopie Konstruktor deklarieren eine nicht explizit eine implizit deklariert. Wenn die Klassendefinition einen Verschiebungskonstruktor oder einen Verschiebungszuweisungsoperator deklariert, wird der implizit deklarierte Kopie-Konstruktor als gelöscht definiert; Ansonsten ist es als default definiert (8.4). Der letzte Fall ist veraltet, wenn die Klasse über einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor verfügt.

Es ist ein Ersatzteil mit ähnlicher Wortlaut für die Kopie Zuordnung in Absatz 18 So Ihre Klasse ist wirklich:

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

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

, weshalb man nicht kopieren-konstruieren. Wenn Sie einen Umzug Konstruktor/Zuordnung bieten, und Sie wollen immer noch die Klasse kopierbar zu sein, müssen Sie explizit die besonderen Mitgliederfunktionen bieten:

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

Sie müssen auch einen Zug Zuweisungsoperator erklären. Wenn Sie wirklich diese speziellen Funktionen benötigen, benötigen Sie wahrscheinlich auch den Destruktor.Siehe Rule of Five.

3

Wenn Sie einen benutzerdefinierten Move-Konstruktor für Ihre Klasse schreiben, wird der Kopierkonstruktor gelöscht. Wenn eine Klasse für ihren Verschiebungskonstruktor ein spezielles Verhalten benötigt, benötigt sie wahrscheinlich ein ähnliches Verhalten in ihrem Kopierkonstruktor. Daher wird der Kopierkonstruktor gelöscht, damit Sie nicht versehentlich das Standardverhalten verwenden.

Wenn Sie Ihren eigenen Zug Konstruktor und verwenden Sie den Standard Copykonstruktor zu definieren, müssen Sie es als default erklären, wie Sie in Ihrer Frage vorgeschlagen:

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

Beachten Sie, dass, wenn Sie definieren ein Wenn Sie einen benutzerdefinierten Move-Konstruktor verwenden, sollten Sie auch über Ihre Zuweisungsoperatoren und den Destruktor nachdenken.

+0

ist es immer noch der Fall in C++ 14, dass der Kopierkonstruktor vom Compiler ausgewählt werden kann oder wird der Compiler nicht den Kopierkonstruktor auswählt und stattdessen fehlschlägt, weil kein Konstruktor verfügbar ist? Ich denke, ich habe gelesen, dass dies sich ändern würde, aber vergessen, ob es in C++ 14 ist oder nicht. –

13

hatte ich das gleiche Problem und es war aufgrund einer schlecht Membervariable definiert:

double const deltaBase = .001; 

diese in Putting verursacht Konstruktor die Kopie gelöscht werden. Entferne das "const" und weise es im Konstruktor zu.

+0

Das gleiche hier, außer dass ich eine Referenz hatte wurde nicht festgelegt und habe dieses Problem: Foo & foo; – kjhf

+0

Ich hatte ein ostringstream-Objekt in der Klasse, die zu diesem Fehler führte. – user3717478