10

A recent question ha attirato la mia attenzione sul modo in cui constexpr has changed in C++14. La nuova funzionalità è che una variabile non locale con durata di memorizzazione statica può essere inizializzata nella fase di inizializzazione statica se il suo inizializzatore è costituito da un costruttore constexpr, anche se il tipo della variabile non è un tipo letterale. Più precisamente, la nuova formulazione [basic.start.init] è:Ordine di distruzione di oggetti non letterali inizializzati staticamente

Un costante inizializzatore per un oggetto o è un'espressione che è un'espressione costante, eccetto che può anche invocare costruttori constexpr per o e i suoi sottooggetti anche se tali oggetti sono di tipo non letterale [Nota: tale classe può avere un distruttore non banale nota finale]. costante inizializzazione viene eseguita [...] se un oggetto con durata statica o stoccaggio filo viene inizializzato da una chiamata di un costruttore, e se l'inizializzazione completa espressione è un inizializzatore costante per l'oggetto [...]

L'esempio tipico è std::unique_ptr, che "non dovrebbe mai essere peggio che scritto a mano":

std::unique_ptr<int> p; // statically initialized by [unique.ptr.single.ctor], 
          // requires no code excution 
int main() 
{ 
    p = std::make_unique<int>(100); 
} 

// p is destroyed eventually 

Prima di questa aggiunta, le variabili inizializzate staticamente erano o di tipo di riferimento o di tipo di oggetto letterale, e quindi aveva banale distruttori. Ma ora una variabile globale inizializzata staticamente può avere un distruttore non banale.

Come viene ordinata una tale chiamata del distruttore rispetto ai distruttori di oggetti globali inizializzati dinamicamente, rispetto ad altri oggetti inizializzati staticamente, e come vengono sequenziate le chiamate del distruttore?

+1

Questo non è nuovo per C++ 14; anche la formulazione precedente lo consente. ('std :: mutex' ha un costruttore' constexpr' in modo che possa sfruttare l'inizializzazione statica, per esempio.) –

+0

@ T.C .: Grazie per il chiarimento! –

risposta

1

[basic.start.term]/1 (N4140) dice:

Se un oggetto è inizializzato statico, l'oggetto viene distrutto nello stesso ordine come se l'oggetto è stato inizializzato dinamicamente.

quanto ho capito, ciò significa che, ai fini della determinig dell'ordine di distruzione, tutti inizializzazione statico è trattata come dinamico (ordinato o non ordinato) ei distruttori sono chiamati in ordine inverso di questa inizializzazione.

+0

Sì, giusto, ma per l'inizializzazione dinamica esiste un insieme di regole per l'ordine (ordinato vs non ordinato). In che modo gli oggetti inizializzati staticamente si adattano a quell'ordinamento in vista di questa regola? –

+0

Vedete, si dice "Le variabili con inizializzazione ordinata definite all'interno di una singola unità di traduzione devono essere inizializzate nell'ordine della loro definizione". Ma questo aiuta solo se l'inizializzazione è ordinata per cominciare, il che non è il caso delle variabili inizializzate staticamente. –

+0

@KerrekSB Penso che sia abbastanza chiaro (aggiornato la mia risposta), ma ad essere sincero non ho testato se questo funziona davvero come penso con gli attuali compilatori –

3

consideri

Se un oggetto è inizializzato statico, l'oggetto viene distrutto nel stesso ordine se l'oggetto è stato inizializzato dinamicamente.

e

Se il completamento del costruttore o inizializzazione dinamico di un oggetto con durata di conservazione statica viene sequenza prima di quello di altro, la realizzazione del distruttore del secondo viene sequenza prima l'iniziazione del distruttore del primo.

Ora,

inizializzazione statica deve essere eseguita prima di ogni inizializzazione dinamica avviene.

Chiaramente questo risponde alla prima domanda: Da p è garantita inizializzazione prima di effettuare qualsiasi inizializzazione dinamica, il distruttore viene chiamato dopo qualsiasi oggetto inizializzato dinamicamente viene distrutto.

Essenzialmente la seconda domanda, cioè che ordine le distruzioni più variabili inizializzate staticamente sono, viene ridotta l'ordinamento della inizializzazione di questi:

dinamica inizializzazione di una variabile non locale con immagazzinaggio statico la durata è ordinata o non ordinata. Le definizioni esplicitamente di membri di dati statici di modelli di classi specializzate hanno ordinato l'inizializzazione di . Altri membri di dati statici di modelli di classe (vale a dire, specializzazioni istanziate in modo implicito o esplicito) hanno l'inizializzazione non ordinata . Altre variabili non locali con durata di memorizzazione statica hanno ordinato l'inizializzazione.

La frase in grassetto include oggetti inizializzati tutto staticamente che non sono membri di dati statici di classi istanziati. Essi sono ordinate entro un'unità di traduzione:

variabili con inizializzazione ordinato definita all'interno di una singola unità traduzione sono inizializzate nell'ordine dei loro definizioni l'unità di traduzione.

Quindi, per riassumere:

  • variabili che sono oggetto di inizializzazione statico e non sono membri di dati static di una classe istanziata vengono distrutti in ordine inverso di definizione in un file di traduzione.

  • ... tali variabili vengono sempre distrutte dopo la distruzione di qualsiasi oggetto inizializzato in modo dinamico.

Tuttavia, nonostante i possibili errori argomentativi, né Clang nè GCC sembrano implementare in questo modo, al momento: Demo.

+0

È questo dal C++ 14 (FD) IS? –

+0

@KerrekSB N4140, che a quanto pare contiene solo modifiche editoriali. Fammi controllare la conformità con l'ultima bozza. – Columbo

+0

@KerrekSB (In alternativa, fornire un collegamento a quale documento dovrei citare e controllare queste virgolette) – Columbo

Problemi correlati