2015-02-05 7 views
6

Questo sembra essere simile a POD structs containing constant member, ma in ordine inverso.Unione contenente strutture volatili

#include <iostream> 

struct A 
{ 
    int a; 
}; 

union U 
{ 
    volatile A a; 
    long b; 
}; 

int main() 
{ 
    U u1; 
    U u2; 

    u1.a.a = 12; 
    u2 = u1; 
    std::cout << u2.a.a << std::endl; 

    return 0; 
} 

g ++ 4.8.3 compila questo codice senza errori e funziona correttamente:

$ g++ -std=c++03 a.cpp -o a_gcc 
$ ./a_gcc 
12 

Ma clang ++ 3.5.1 produce un errore (ho avvolto manualmente il messaggio di errore per mantenere la casella codice scrolling):

$ clang++ -std=c++03 a.cpp -o a_clang 
a.cpp:8:7: error: member function 'operator=' not viable: 'this' 
argument has type 'volatile A', but function is not marked volatile 
union U 
    ^
a.cpp:3:8: note: 'operator=' declared here 
struct A 
    ^
a.cpp:20:5: note: implicit copy assignment operator for 'U' first 
required here 
     u2 = u1; 
     ^
1 error generated. 

Does C++ 03 consentire al programma di copia-assegnare un'unione che contiene le strutture volatili? Non ho trovato nulla nello standard C++ 03 che definisce il costruttore di copie predefinito di un sindacato.

Mi piacerebbe sapere quale compilatore è corretto o se lo standard non è chiaro su quel punto.

Modifica: Ho scoperto che se uso la costruzione di copia anziché l'assegnazione della copia, sia clang ++ che g ++ compileranno il programma senza errori. In particolare se cambio main essere:

int main() 
{ 
    U u1; 

    u1.a.a = 12; 
    U u2 = u1; 
    std::cout << u2.a.a << std::endl; 

    return 0; 
} 

.. allora funzionerà. Mi chiedo perché vengono trattati in modo diverso da clang ++.

+0

Cosa succede se si aggiunge un operatore di assegnazione definito dall'utente in 'union U':' volatile U & operator = (const volatile U &) volatile'? O forse solo con alcune di quelle volatili? –

+0

Perché non rendere volatili le istanze del sindacato invece di rendere instabili i membri del sindacato? Sembra più facile ragionare sul suo comportamento in questo modo. – BlamKiwi

+0

@JohnZwinck Perché non causerà questo problema. – qbt937

risposta

0

In C++ 11, il costruttore copia dell'unione può essere eliminato. Lo vediamo da una nota in [class.union], §9.5 in N4140:

[Nota: Se un membro di dati non-statico di un'unione ha un costruttore di default non banale (12.1) , copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), o destructor (12.4), la corrispondente funzione membro dell'unione deve essere fornita dall'utente o sarà essere implicitamente cancellato (8.4.3) per l'unione. -end nota]

E in [class.copy], §12.8/25, si vede che il nostro union ha una copia non banale costruttore:

Una copia/spostamento operatore di assegnazione per la classe X è banale se non è fornito dall'utente, la sua lista tipo-parametro è equivalente alla lista-tipo-parametro di una dichiarazione implicita, e se ...
- [..]
- classe X ha nessun membro di dati non statici di tipo volatile qualificato, e

Ma quella linea particolare in [class.copy] solo è stato aggiunto a seguito di Is a volatile-qualified type really a POD? Prima di allora, una tale classe sarebbe ancora considerato di avere un costruttore di copia banale.

Quindi è a mia conoscenza che in C++ 03 non c'è indicazione che il costruttore di copie dell'unione debba essere cancellato, e in C++ 11, c'è qualche indicazione su questo, ma non è normativo.

+0

Si noti che la regola citata in realtà non si applica, poiché è il sindacato stesso il cui operatore di assegnazione delle copie non è banale, ma la regola parla degli operatori per i membri ... e dell'operatore di assegnazione copia per 'classe A' * è * banale. –

+0

@BenVoigt Hm. Quindi non ho ottenuto nulla. – Barry

+0

Penso che questo sia ancora valido, ma decisamente non normativo. –