Ripetendo il messaggio di errore:
main.cpp(56): error C2280: 'Rect &Rect::operator =(const Rect &)': attempting to reference a deleted function
Questo è abbastanza chiaro: la funzione membro operator=
con il parametro const Rect &
è stata delete
d, ma il codice tenta di chiamare sulla linea test = Rect();
.
È poi dire:
Il compilatore cerca di dirmi che, il costruttore di copia della classe Rect è una funzione eliminata
Tuttavia, è frainteso l'errore. L'errore riguarda la funzione operator =
, che viene chiamata operatore di assegnazione copia.Questa è una funzione diversa da copy constructor, che assomiglierebbe a Rect::Rect(const Rect &)
.
Lei dice che si è tentato di aggiungere:
Rect& operator=(const Rect&) = default;
Tuttavia, questo farebbe alcuna differenza. La funzione operator=
generata dal compilatore è delete
d perché non è possibile per il compilatore generarne una (la spiegazione per questo viene fornita di seguito); scrivere = default;
non cambia questo. È necessario scrivere il proprio corpo per operator=
che esegue le azioni che si desidera eseguire quando si verifica un compito.
In Standard C++ non è consentito avere una struttura anonima, per non parlare di una struttura anonima all'interno di un'unione anonima. Quindi sei davvero fuori da solo qui. Le regole che il compilatore sta utilizzando in merito a operator=
, costruttore di copia, ecc. Non sono coperte da alcuno Standard.
una versione del Rect
che è compilabile in standard C potrebbe essere simile:
class Rect
{
public:
struct S1 {
Vector p1, p2;
S1(Vector p1, Vector p2): p1(p1), p2(p2) {}
};
struct S2 {
float p1x, p1y, p2x, p2y;
};
union {
struct S1 s1;
struct S2 s2;
};
Rect() : s1({0, 0}, {0, 0}) {}
Rect(Vector p1, Vector p2) : s1(p1, p2) {}
};
Fin qui, tutto bene. Per questa classe, lo operator=
implicitamente dichiarato è definito come cancellato. Per capire perché, dobbiamo prima esaminare le funzioni speciali dichiarate implicitamente per l'unione anonima, perché il comportamento della funzione implicitamente dichiarata per una classe dipende dal comportamento della stessa operazione per ciascuno dei suoi membri.
La regola qui rilevante per l'unione è C++ 14 [class.union]/1:
Se un membro di dati non-statico di un sindacato ha un costruttore di default non banale, costruttore di copia , spostare costruttore, copiare l'operatore di assegnazione, spostare l'operatore di assegnazione o distruttore, la funzione membro corrispondente dell'unione deve essere fornita dall'utente o sarà implicitamente delete
d per l'unione.
Vector
ha un non banale operator=
, perché si scrive il proprio corpo per esso. Pertanto, S1
ha un valore non banale operator=
, perché ha un membro con non banale operator=
, quindi, in base alla citazione precedente, il operator=
implicitamente dichiarato per l'unione è delete
d.
Si noti che non vi è alcun errore sul copy-constructor: Vector
fa ha un banale copy-constructor, quindi anche il sindacato lo fa.
Per correggere questo errore che si possa fare una delle due cose:
- Change
Vector::operator=
di essere banale, sia rimuovendo la tua definizione del tutto, o rendere = default;
- Write
operator=
per la Rect
classe
Ora, come scriveresti il tuo operator=
? Lo fai s1 = other.s1;
o lo fai s2 = other.s2;
? Il compilatore non può saperlo da solo, che è la ragione per cui lo operator=
implicitamente dichiarato viene eliminato.
Ora, sembra che trascurato (accidentalmente o deliberatamente) la regola di membri attivi in C++:
In un'unione, tutt'al più uno dei membri di dati non statici può essere attivo in qualsiasi momento
Questo significa che se s1
è l'ultimo set di membri, allora dovreste fare s1 = other.s1;
. Oppure se s2
è l'ultimo membro impostato, dovresti fare s2 = other.s2;
.
Il costruttore di copie non si imbatte in questo problema perché è banale: il compilatore può generare una copia bit-saggio e che implementerà correttamente la copia indipendentemente dal membro attivo. Ma dal momento che il tuo operator=
non è banale, non sarebbe possibile.
Ad esempio, immagina se hai effettivamente un'unione di std::string
e std::vector
- la copia bit a bit non funziona per nessuno di questi e devi sapere quale è attivo per poter eseguire la copia.
Ribadendo: In serie C++ non è permesso di leggere un membro di un sindacato diverso da quello più recente scritto. Non puoi usare i sindacati per l'aliasing. C++ ha altri strumenti linguistici per ottenere ciò che potresti fare in C con l'aliasing unione, see here for more discussion.
In base alla scelta dei membri per le strutture anonime, sospetto che questo è ciò che si intendeva fare. Se vuoi davvero andare avanti con questo approccio, facendo affidamento sul tuo compilatore per implementare l'aliasing unione come un'estensione non standard, allora il mio consiglio sarebbe di usare il valore predefinito operator=
per la tua classe Vector
.
Si sta utilizzando [Unrestricted_unions] (https://en.wikipedia.org/wiki/C%2B%2B11#Unrestricted_unions) (che non è banale). – Jarod42
Non ho accesso a VS2015. Ma, se si definisce un operatore di assegnazione della copia non predefinito per 'Rect()', il programma si compila usando 'clang ++' ma non con 'g ++'. Esempi: [clang ++] (https://goo.gl/dCcIJc) e [g ++] (http://ideone.com/tFUnFt). Funziona con VS2015? – crayzeewulf
grazie per le vostre risposte Sì, penso che il problema fosse l'utilizzo degli operatori di copia e assegnazione predefiniti. Forse c'è un problema a generarli automaticamente quando si utilizza questo costrutto di unione (senza vincoli). Quando li sostituisco con operatori di copia e assegnazione non predefiniti, non ci sono problemi. –