Perché alcune variabili const riferimento ad alcune variabili const esportate ottenere il valore 0?
-
06-09-2019 - |
Domanda
Si consideri il seguente. Ho due costanti esportati come segue:
// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;
e
// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
Queste costanti sono ora riferimento qualche altro posto per definire due costanti statici (localmente visibili):
// someotherfile.cpp
#include "somefile.h"
static const double cAnotherDouble = 1.1*cMyConstDouble;
static const double cAnotherDouble2 = 1.1*cMyConstDouble2;
printf("cAnotherDouble = %g, cAnotherDouble2 = %g\n",
cAnotherDouble, cAnotherDouble2);
che produce il seguente output:
cAnotherDouble = 3.454, cAnotherDouble2 = 0
Perché il doppio secondo 0? Sto utilizzando .NET 2003 compilatore C ++ (13.10.3077).
Soluzione
A causa cMyConstDouble è dichiarata come extern, compilatore non è in grado di assumere il suo valore e non genera un tempo di compilazione di inizializzazione per cMyConstDouble2. Poiché non è compilare volta inizializzato il cMyConstDouble2, l'ordine di inizializzazione relative al cAnotherDouble2 è casuale (non definito). Vedere inizializzazione statico fiasco per più informazioni.
Altri suggerimenti
Non ho intenzione di immergere il dito del piede nelle questioni di extern qui, ma perché semplicemente non mettere i const nei file di intestazione appropriati e dimenticare "l'esportazione" utilizzando extern? Questo è il modo const dovrebbero essere utilizzati in C ++, e perché hanno il collegamento interno.
In altre parole:
// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
e # include il file che ovunque ne avete bisogno.
Questa è cosa pericolosa da fare come una variabile statica in un file sorgente dipende dalla un'altra variabile statica in un altro file cpp. Controllare statica di inizializzazione fiasco per ulteriori informazioni.
Se si modifica l'inizializzazione di cMyConstDouble2
a questo qui:
const double cMyConstDouble2 = 2.5*3.14;
Poi il programma dovrebbe comportarsi in modo corretto. La ragione di questo è che le variabili che
- tipo hanno POD
- vengono inizializzati con espressioni costanti (1)
vengono inizializzati in fase di inizializzazione statico. Questi includono inizializzazioni
- Zero inizializzazione di tutti oggetti aventi durata di conservazione statica
- Inizializzazioni dei baccelli inizializzate con espressioni costanti
le variabili indicate, solo soddisfa cMyConstDouble
entrambe le condizioni di essere inizializzato completamente in fase di inizializzazione statico. Tuttavia, cMyConstDouble2
no, fin dalla sua inizializzatore non soddisfa i requisiti di un'espressione costante. In particolare, essa comprende una variabile che non dispone di tipo integrale (qui, è flottante punto). Tuttavia, in virgola mobile letterali sono ammessi in aritmetiche espressioni costanti. Questo è il motivo 2.5*3.14
è un'espressione costante aritmetica. Ed è per questo cambiare l'inizializzatore a che richiederà di essere inizializzato in modo statico.
Che cosa accadrà con cMyConstDouble2
se si rimane con l'espressione non costante? La risposta è, non si sa. Lo Standard permette tale variabile da inizializzare staticamente, ma non richiede di farlo. Nel tuo caso, è stato inizializzato in modo dinamico - così il suo valore solo dopo il tempo di inizializzazione statico era ancora pari a zero. Per ottenere una sensazione di come complicato che è, ecco un esempio:
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0
Se l'inizializzazione dinamica non cambia qualsiasi altra variabile di archiviazione statica (soddisfatte in tuo codice) e quando l'inizializzazione statica produrrebbe lo stesso valore come sarebbe prodotto da inizializzazione dinamica quando tutti non oggetti necessario per essere inizializzato in modo statico sarebbe stato inizializzato in modo dinamico (anche soddisfatto in tuo codice) - allora la variabile è permesso di essere inizializzato in modo statico. Queste due condizioni sono soddisfatte anche nel codice qui sopra per entrambe le variabili d2
e d1
:
L'analisi dei d2
-
= d1
non cambia qualsiasi altra variabile di memorizzazione static - Quando sia
d2
ed1
vengono inizializzati dinamicamente, quindid2
sarebbe inizializzato a0.0
, perchéd2
viene definito primad1
, e l'inizializzazione dinamica did2
sarebbe afferrare il valore did1
come dello stato appena dopo inizializzazione statico (dove zero solo inizializzazione deld1
ha avuto luogo).
L'analisi dei d1
-
= fd()
non cambia qualsiasi altra variabile di memorizzazione static - Quando sia
d2
ed1
vengono inizializzati in modo dinamico, quindi= fd()
inizializzad1
a1.0
.
Quindi, il compilatore può inizializzare d1
staticamente a 1.0
, perché sono soddisfatte entrambe le condizioni per facoltativo-static-inizializzazione.
-
Se il compilatore decide per inizializzare
d1
ed2
modo dinamico, quindid2
verrà inizializzato per0.0
, dal momento che afferrare il valore did1
come era subito dopo l'inizializzazione a zero. -
Tuttavia , se il compilatore decide per inizializzare
d1
staticamente ed2
dinamico, quindi verrà inizializzatod2
a1.0
, in quanto l'inizializzazione dinamica did2
sarà afferrare il valore dell'inizializzazione deld1
come è stato appena dopo initializatio staticon.
Non sono sicuro di quale sia il valore di d2
è quando d1
e d2
viene inizializzato in modo statico, però. Cioè, se d2
dovrebbe afferrare il 0.0
o 1.0
, dal momento che non esiste un ordine definito per l'inizializzazione statica.
(1) espressioni costanti includono aritmetiche espressioni costanti troppo (non solo integrali espressioni costanti), quando si considera ordine di inizializzazione di oggetti con durata di conservazione statica.