2014-09-25 23 views
5

Contesto: Sono in un ambiente con codice grande in cui l'ordine non definito in cui vengono eseguiti i costruttori globali è problematico. Quindi ho una classe personalizzata progettata per ritardare l'inizializzazione fino al primo utilizzo. Tutta la sua magia si verifica all'interno delle sue funzioni operatore * e operatore->; sono l'unica cosa definita. Memorizza anche alcuni stati al suo interno, per rendere disponibile la funzione di inizializzazione automatica. Questo stato deve, ovviamente, essere POD, in modo che l'intera classe sia POD, in modo che possa essere completamente impostata prima che il codice di chiunque inizi a funzionare, in modo che tutto il codice possa usare tutti i globali ovunque, senza il timore che i globali non si nascondano " è stato ancora istituito.C++ 11: un operatore di assegnazione impedisce a un tipo di essere POD e pertanto viene inizializzato a livello globale?

Un po 'di tempo fa qualcuno ha aggiunto un operatore di assegnazione privato, mai definito, in modo che il tipo non sarebbe mai stato assegnato a (non è progettato per mai cambiare comunque). Ora qualcun altro sta dicendo che la lezione è rotta perché non è POD. Se invece di essere dichiarato-ma-non-definito, lo dichiaro come "= delete", sto pensando che sia in qualche modo migliore. E infatti, con questa modifica, std :: is_pod <> :: value restituisce true per il tipo.

Ma come un operatore di assegnazione impedisce a un tipo di essere POD? Pensavo che i requisiti fossero solo che doveva avere solo membri di dati pubblici, nessun metodo virtuale e nessun costruttore o distruttore.

E più al punto per la mia situazione: la presenza di un operatore di assegnazione non definito impedisce alla classe di essere inizializzata al momento di inizializzazione globale, insieme a tutti gli altri POD globali?

esempio ridotto:

struct LazyString { 
    const char *c_str; 

    bool has_been_inited; 
    string *lazy_str_do_not_use_directly; 

    string &operator*() { return *get(); } 
    string *operator->() { return get(); } 

private: 
    string *get() { 
    // The real code uses a mutex, of course, to be thread-safe. 
    if (!has_been_inited) { 
     lazy_str_do_not_use_directly = new string(c_str); 
     has_been_inited = true; 
    } 
    return lazy_str_do_not_use_directly; 
    } 

    // Does this make the class non-POD? 
    // If so, does that mean that global variables of this type 
    // will not be initialized at global-initialization time, that wonderful 
    // moment in time where no code has yet been run? 
    void operator=(const LazyString&); 

    // If I do this instead, it breaks C++03 compatibility, but is this somehow better? 
    void operator=(const LazyString&) = delete; 
}; 

LazyString lazy = { "lazy" }; 

int main(int argc, char *argv[]) { 
    std::cout << *lazy; 
} 
+0

Produrre la gestione della memoria del proprio heap non è quasi mai una buona idea. Perché pensi di aver bisogno di questo? (intendevi implementare s.th. come [copy-on-write] (http://stackoverflow.com/questions/12199710/legality-of-cow-stdstring-implementation-in-c11)) –

+1

Sei confondendo POD-ness e inizializzazione statica. Né dipende dall'altra. –

+0

Poiché tutti i membri dati sono visibili pubblicamente, tale dichiarazione costituisce un POD, sì. ** NOTA: ** Avrai effetti collaterali indesiderati riguardo alla 'nuova stringa (c_str);' nella tua _lazy initialization_, quando copi/assegni questo tipo di POD. –

risposta

6

Fa un operatore di assegnazione prevenire un tipo di essere POD

Sì. Un tipo di POD deve essere banale; e così deve essere banalmente copiabile; e quindi non deve avere operatori non banali di copia o spostamento.

Qualsiasi operatore fornito dall'utente non è banale, quindi dichiarare il costruttore di copie rende la classe non banale, e quindi non POD.

e quindi inizializzato a livello globale?

No. Qualsiasi tipo di codice istantaneo, POD o non, può essere una variabile globale.

UPDATE: Dal commento, si intendeva chiedere:

Può essere statico, piuttosto che in modo dinamico, inizializzato?

Sì, poiché ha un costruttore banale; finché l'inizializzatore è un'espressione costante. Nell'esempio, { "lazy" } è un'espressione costante, pertanto LazyString può essere inizializzato staticamente.

La caratteristica importante qui è che ha un costruttore banale, non che è POD. POD significa che soddisfa anche vari altri requisiti, non rilevanti per l'inizializzazione.

+0

Credo che la frase corretta sia "Qualsiasi utente - ** fornito ** operatore non è banale". Ad esempio, 'class foo {foo & operator = (foo const &) = default; }; 'ha un banale operatore di assegnazione copia dichiarato dall'utente. –

+0

@CassioNeri: Grazie per la correzione. È facile perdere traccia di queste sfumature di significato. –

+0

Hai detto "Qualsiasi tipo di elemento istantaneo, può essere una variabile globale", e mentre è vero, questo non risponde alla mia domanda. Ad esempio, se ho foo1.cc, contenente l'inizializzazione globale "int foo = printf (" Hello World \ n ");", e anche foo2.cc, contenente l'inizializzazione globale "extern int foo; int bar = pippo;", quindi non posso sapere, per lo standard C++, quale barra dei valori finirà con, perché entrambe sono inizializzazioni dinamiche. Ecco perché sto cercando di eliminare tutte le inizializzazioni dinamiche ... ma non so se il fatto che sto assegnando tutti i campi di questa struttura con i POD è sufficiente. – jorgbrown

2

C++ ha diverse fasi di inizializzazione per le variabili non locali con durata di memorizzazione statica (la variabile globale ricade in questa categoria) - indipendentemente dal fatto che il tipo sia un POD o meno.

  • nullo inizializzazione avviene prima di qualsiasi altra inizializzazione
  • costante inizializzazione si è svolto
  • inizializzazione dinamica

I primi due tipi di inizializzazione deve avvenire prima inizializzazione dinamica. L'inizializzazione dinamica è la situazione in cui l'ordine di inizializzazione può essere difficile da impostare. Alcune inizializzazioni dinamiche non sono ordinate, alcune sono ordinate all'interno di un'unità di traduzione, ecc.

Anche se la variabile globale non è POD, si può essere certi che l'inizializzazione zero avrà avuto luogo prima di qualsiasi init dinamico.

Vedere C++ 11 3.6.2 "Inizializzazione di variabili non locali" per i dettagli.

+0

A quanto ho capito, l'inizializzazione dinamica può fare riferimento a globals da altri file. Come autore di un altro file, voglio essere sicuro che i miei globals siano disponibili per tutte le var di inizializzazione dinamica. Cioè, voglio essere sicuro che la mia classe sia inizializzata a tempo di inizializzazione costante. So che se la mia classe fosse POD, o dichiarata constexpr, che sarebbe garantita l'inizializzazione durante la fase di "inizializzazione costante". Ma la mia classe LazyString è garantita per essere eseguita prima di init dinamico? – jorgbrown

+0

L'inizializzazione statica ha luogo prima di qualsiasi inizializzazione dinamica nel programma. Quindi l'oggetto globale 'LazyString' viene inizializzato prima che l'inizializzazione dinamica di qualsiasi altro oggetto possa chiamare' LazyString :: get() '. –