2014-10-30 4 views
7

Il seguente codice è legale (in C++ 11/14)?È legale attivare i sindacati nidificati tramite l'indirizzo dei loro membri?

bool foo() { 
    union bar { int i; bool b; }; 
    union baz { char c; bar b; }; 
    auto b = baz{'x'}; 
    auto barptr = &b.b; 
    auto boolptr = &barptr->b; 
    new (boolptr) bool{true}; 
    return b.b.b; 
} 

Questo esempio è stupido, ma sto giocando intorno con un variadic variant implementazione che utilizza i sindacati nidificate al posto di un blocco char [] per i membri variante, e permettendo questo renderà il mio attuale tentativo di pulitore costruttore di copia .

Per rompere il basso in due subquestions:

  1. è l'assegnazione di boolptr accedendo un membro della barptr legale anche se b.b non è attiva?
  2. La costruzione sul posto di boolptr attiva b.b e b.b.b?

I riferimenti allo standard sarebbero apprezzati.

+0

forse parzialmente risposto qui: http://stackoverflow.com/questions/11373203/accessing-inactive-union-member-undefined –

+0

C'è qualche motivo specifico per Supponiamo che l'espressione 'bb' sia più legale di' * (& (bb)) '? Perché altrimenti è abbastanza ovvio che entrambi sono ugualmente legali (nessuno sta seriamente argomentando che "b.b' è senza legge!) – MSalters

risposta

2

Come con così tante domande sui sindacati e il tipo di punteggiatura, non è chiaro se il tuo programma ha un comportamento definito, sebbene mi aspetto fortemente che si comporti come previsto in qualsiasi implementazione sana. Quello che posso dire con certezza è che this program:

#include <memory> 
#include <new> 

template <typename T> 
inline void destruct(T& t) { t.~T(); } 

template <typename T, typename...Args> 
inline void construct(T& t, Args&&...args) { 
    ::new((void*)std::addressof(t)) T(std::forward<Args>(args)...); 
} 

template <typename T> 
inline void default_construct(T& t) { 
    ::new((void*)std::addressof(t)) T; 
} 

bool foo() { 
    union bar { int i; bool b; }; 
    union baz { char c; bar b; }; 
    auto b = baz{'x'}; 
    destruct(b.c); 
    default_construct(b.b); 
    construct(b.b.b, true); 
    return b.b.b; 
} 

è standard-compliant, ha esattamente gli effetti che desideri, e compiles to exactly the same assembly as the original program in modern compilers. Original:

foo(): 
    movl $1, %eax 
    ret 

Guaranteed-compliant:

foo(): 
    movl $1, %eax 
    ret 
+0

Interessante, ma piuttosto inutile. Non c'è carenza di programmi che vengono ottimizzati completamente, lasciando solo 'return 1;' –

+0

Come si deduce l'argomento del template 'Args' su' default_construct'? Non è usato in un contesto deducibile. –

+0

@BenVoigt Clang non si lamenta di 'Args', potrebbe sia clang che gcc hanno lo stesso bug? – Casey

Problemi correlati