2015-06-05 22 views
6

clang++ non consente mai default initialization of a const variable of class-type without a user-defined constructor; g++ è leggermente meno restrittivo (vedi sotto). Secondo this answer, questo è dovuto al fatto che i tipi di POD "non sono inizializzati di default." Se capisco correttamente, ciò significa che l'inizializzazione di default non richiama il costruttore di default, né invoca l'inizializzazione del valore, quindi i membri di dati all'interno del tipo POD non sono inizializzati. Ovviamente non ha senso avere un tipo const POD con valori non inizializzati, poiché possono mai essere inizializzati e quindi non sono sicuri da usare.Quando e come inizializzare di default una variabile const?

Ci sono alcune varianti di questa situazione:

  1. Il tipo è tecnicamente "POD", ma non contiene membri di dati (solo funzioni). (clang++ non tratta questo come un caso speciale, né, credo, fa lo standard, ma g++ LO PERMETTE, anche quando il costruttore è contrassegnato explicit.)
  2. Un costruttore vuoto è definita utilizzando {}. (Questa soluzione è consigliata nella pagina clang che descrive il problema.)
  3. Il costruttore predefinito è dichiarato =default. (C++ 11 in poi, il tipo è ancora considerato POD, quindi né il compilatore né lo standard trattano come un caso speciale.)
  4. L'inizializzazione di aggregazione viene esplicitamente invocata utilizzando {}, che (se ho capito correttamente) diventa inizializzazione del valore . (C++ 11 in poi;. Entrambi i compilatori-e, credo, lo standard-lo permettono)

Nel primo caso, non ci possono essere non inizializzate membri, quindi è chiaro perché qualsiasi istanza della la classe stessa sarebbe mai considerata "non inizializzata", indipendentemente dal fatto che sia const o meno. Dal momento che g++ consente questo comportamento, è sicuro da usare? Perché è vietato da clang++ e dallo standard? (E ci sono altri casi in cui g++ permette POD-default-inizializzazione dove clang++ non?)

Nel secondo e terzo caso, l'esigenza di utilizzare {} invece di =default sembra strano per me. MODIFICA:this question spiega abbastanza bene la differenza, quindi ho rimosso la parte della domanda chiedendo la distinzione. (Io continuo a pensare che sia un aspetto terribilmente confuso della lingua, però.)

Infine, sarà Foo f{} sempre zero-inizializzare i membri di tipo built-in se Foo::Foo(void) è {}, =default, o implicitamente dichiarata?

+0

Esiste un caso d'uso per un tipo const POD senza variabili membro? Puoi anche usare uno non-const, poiché non ci sono membri che potrebbero essere erroneamente cambiati. –

+0

@MattMcNabb Non ne sono sicuro. Questo è uno schema che ricorre ripetutamente nel codice di un collega, in funzioni di fabbrica (o ... qualcosa del genere). Cercherò di ricordare di chiedere a quel collega domani quale sia l'intento. –

+0

Un costruttore definito con '{}' non è un costruttore banale. – 0x499602D2

risposta

5

Poiché g ++ consente questo comportamento, è sicuro da usare?

Sicuro in che senso? Ovviamente non è attualmente portatile. Tuttavia, non ti darà risultati inaspettati su g ++.

Perché è vietato da clang ++ e dallo standard?

Presumibilmente la commissione sia non pensare quando hanno messo il "costruttore fornita dall'utente richiesto" regola in C++ 98, o ha deciso che speciale tubiero classi POD vuoti non vale la specifica complessità ; clang ++ sta seguendo lo standard. Tuttavia, lo standard è likely going to change per consentire in genere di scrivere const Foo f; finché il costruttore, infatti, inizializzerà ogni subobject.

Infine, sarà Foo f{}; sempre zero-inizializzare i membri del built-in tipo se Foo::Foo(void) è {}, =default, o implicitamente dichiarata?

Sì per gli ultimi due. No per il primo. Quella conta come fornita dall'utente, quindi l'inizializzazione del valore non esegue l'inizializzazione zero prima di chiamare il costruttore predefinito.

+0

Intendevo davvero "sicuro" nel senso "risultati inattesi". Ancora una volta, bel collegamento open-standard; come li trovi così velocemente (o del tutto)? Inoltre, quando si dice "l'inizializzazione del valore non esegue l'inizializzazione zero prima di chiamare il costruttore predefinito", si intende che l'inizializzazione zero non avverrà (necessariamente) * affatto *? Quindi cambiare da '= default' a' {} 'può effettivamente * introdurre * bug di inizializzazione impropria? –

+0

@KyleStrand 1) Questa particolare differenza di g ++/clang ++ è stata richiesta su SO prima, quindi so che c'è un problema di open core su questo :) 2) Sì, non è garantito che accada, anche se l'implementazione può clobare la memoria piace (dato che nessun programma ben definito può osservarlo). Tecnicamente parlando, è indeterminato, e leggerlo causa UB (modulo alcune eccezioni per 'unsigned char'); 3) Sì. –