E 'una cattiva pratica usare variabili costanti con scope globale in C ++?

3

Quindi stavo leggendo la sezione 3.2 (Una sezione delle regole di definizione) nel ultima bozza di lavoro dello standard C ++ e ci siamo imbattuti in questo:

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

Questo mi è sembrato strano per quanto riguarda la parte variable , perché se un file di intestazione ha una variabile costante globale e funziona in questo modo:

const int k = 10;

int foo(const int &i) {
    return 0;
}

Che cosa succede se per errore chiami foo(k) ? Sembra che questo risulterebbe in UB perché k ha linkage interno (cioè ogni unità di traduzione avrebbe la propria definizione di k , quindi non ci sarebbe esattamente una definizione ... in quel programma ). Quindi, in pratica, se hai una qualsiasi variabile const con ambito globale, dovresti ricordare di non chiamare nessuna funzione che prende il suo riferimento o indirizzo.

    
posta Justin 24.07.2015 - 21:00
fonte

2 risposte

5

L'unica regola di definizione nello standard non viene "visualizzata" una sola volta, ma ha un'unica definizione. Per esempio. se const era in un file di intestazione, potrebbe apparire in più unità di traduzione, ma tutte avrebbero la stessa definizione singola. Per inciso, il linker potrebbe quindi piegarli tutti in un'unica posizione (se è richiesta persino una posizione).

What if you mistakenly call foo(k)? It seems like this would result in UB...

Non ci sarebbe nessun UB qui. Il collegamento interno va bene, è const e c'è solo una sua definizione.

Questo (il const int i = 1234; ) ha un caso di uso generale per valori costanti a livello di programma, ad es. const double pi = 3.1415 , const std::size_t answer = 42; ecc.

In una nota a margine, hai chiesto espressamente le variabili globali, ma posizionare costanti e simili in spazi dei nomi sono sempre un buon modo per evitare scontri sui nomi ecc.

    
risposta data 24.07.2015 - 21:23
fonte
2

Sei vicino, ma non del tutto. La cattiva pratica qui è dichiarare le variabili globali al di fuori di uno spazio dei nomi .

namespace jucestain {
    const int k = 10;

    int foo(const int &i) {
        return 0;
    }
} // end namespace jucestain

Dopo averlo inserito in uno spazio dei nomi, foo(k) verrà risolto solo in foo(10) se hai using namespace jucestain; nella parte superiore del file. Altrimenti dovresti scrivere jucestain::foo(jucestain::k) , che è piuttosto difficile da fare per caso.

E anche senza uno spazio dei nomi, non c'è un comportamento indefinito perché k ha ancora solo una definizione per unità di traduzione, ed è l'unità di traduzione che conta (altrimenti il file di intestazione contenente k non dovrebbe essere "incluso" in più posti "per cominciare).

    
risposta data 24.07.2015 - 21:24
fonte

Leggi altre domande sui tag