2015-07-07 16 views
16

Questo frammento è stato compilato senza errori in Visual Studio 2013 (versione 12.0.31101.00 Aggiornamento 4)C++ Compiler errore C2280 "il tentativo di fare riferimento a una funzione eliminata" in Visual Studio 2013 e il 2015

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

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

mentre viene compilato con questo errore in Visual Studio 2015 RC (versione 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 ========== 

credo che il compilatore fornito con Visual Studio 2015 genera il costruttore di copia e lo contrassegna come =delete e così ottengo l'errore C2280 (che, a proposito, non riesco a trovare documentato su msdn.microsoft.com).

Ora, diciamo che ho un codebase che è compilabile con Visual Studio 2013 (e funziona perché si basa sul codice generato automaticamente dal compilatore) ma non è compilabile con Visual Studio 2015 a causa di C2280, come posso risolvere il problema?

Stavo pensando di dichiarare classe A in questo modo:

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

mi sto perdendo qualcosa?

+1

Insieme a quello "A & operator = (A &&) ;" e "A & operator = (const A &);" – Jagannath

risposta

23

Da [class.copy]/7, l'enfasi è mia:

Se la definizione della classe non dichiara esplicitamente un costruttore di copia, una non-esplicito è dichiarato in modo implicito. Se la definizione di classe dichiara un costruttore di spostamenti o un operatore di spostamento, la copia implicita dichiarata della copia viene definita come cancellata; altrimenti, è definito come predefinito (8.4). Il secondo caso è deprecato se nella classe esiste un operatore di assegnazione copia dichiarato dall'utente o un distruttore dichiarato dall'utente.

C'è una sezione equivalente con una formulazione simile per l'assegnazione copia al paragrafo 18. Quindi la tua classe è davvero:

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

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

che è il motivo per cui non è possibile copiare-costruirlo. Se si fornisce una mossa costruttore/assegnazione, e si vuole ancora la classe di essere copiabile, si dovrà prevedere esplicitamente quelle funzioni membro speciali:

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

Sarà inoltre necessario dichiarare un operatore di assegnazione mossa. Se hai davvero bisogno di queste funzioni speciali, probabilmente avrai anche bisogno del distruttore.Vedi Rule of Five.

3

Se si scrive un costruttore di spostamento definito dall'utente per la classe, il costruttore di copie verrà eliminato. Questo perché se una classe ha bisogno di un comportamento particolare per il suo costruttore di spostamenti, probabilmente ha un comportamento simile nel suo costruttore di copie, quindi il costruttore di copie verrà eliminato per impedirti di utilizzare inavvertitamente il comportamento predefinito.

Se si vuole definire il proprio costruttore mossa e utilizzare il costruttore di copia di default, è necessario dichiararla come default, come da te suggerito nella tua domanda:

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

Si noti che se si definisce un costruttore di mosse personalizzato, dovresti pensare anche ai tuoi operatori di assegnazione e al distruttore.

+0

è ancora il caso in C++ 14 che il costruttore di copie possa essere selezionato dal compilatore, oppure il compilatore non seleziona il costruttore di copia e invece fallisce perché non ha costruttore disponibile? Penso di aver letto che questo sarebbe cambiato, ma ho dimenticato se è in C++ 14. –

13

Ho avuto lo stesso problema ed è stato a causa di una variabile membro mal definita:

double const deltaBase = .001; 

Mettendo questo farà sì che il costruttore di copia da eliminare. Sbarazzati di "const" e assegnali al costruttore.

+0

Lo stesso qui, tranne che avevo un riferimento che non è stato impostato e ha avuto questo problema: Foo & foo; – kjhf

+0

Ho avuto un oggetto ostringstream nella classe che ha portato a questo errore. – user3717478