2009-09-04 13 views
11

Il modo tipico per definire un numero intero costante da utilizzare all'interno di una funzione è:C'è un motivo per usare enum per definire una singola costante nel codice C++?

const int NumbeOfElements = 10; 

lo stesso per l'utilizzo all'interno di una classe:

class Class { 
... 
    static const int NumberOfElements = 10; 
}; 

Può quindi essere utilizzato come una matrice di dimensioni fisse legato che significa che è noto al momento della compilazione.

Molto tempo fa i compilatori non hanno sostenuto la seconda sintassi e questo è il motivo per cui le enumerazioni sono stati utilizzati:

enum NumberOfElementsEnum { NumberOfElements = 10; } 

Ora con quasi ogni compilatore ampiamente utilizzato supporta sia l'in-funzione di const int e l'in-class static const int sintassi è c'è qualche ragione per usare l'enum per questo scopo?

risposta

23

Il motivo è principalmente la brevità. Prima di tutto, un enum possono essere anonimi:

class foo { 
    enum { bar = 1 }; 
}; 

Questo introduce efficacemente bar come costante integrale. Si noti che quanto sopra è più corto di static const int.

Inoltre, nessuno potrebbe scrivere &bar se è un membro enum. Se si esegue questa operazione:

class foo { 
    static const int bar = 1; 
} 

e quindi il client della classe fa questo:

printf("%p", &foo::bar); 

poi otterrà un errore di linker in fase di compilazione che foo::bar non è definito (perché, beh, come un lvalue, non lo è). In pratica, con lo standard al momento attuale, viene utilizzato ovunque bar dove non è richiesta un'espressione costante integrale (ad es.dove è semplicemente consentito), richiede una definizione fuori classe di foo::bar. I luoghi in cui è richiesta tale espressione sono: enum inizializzatori, case etichette, dimensione di matrice in tipi (eccetto lo new[]) e argomenti modello di tipi interi. Pertanto, l'utilizzo di bar in qualsiasi altro punto richiede tecnicamente una definizione. Vedi C++ Core Language Active Issue 712 per maggiori informazioni - non ci sono ancora risoluzioni proposte. In pratica, la maggior parte dei compilatori in questi giorni sono più indulgenti in questo, e ti permetterà di farla franca con la maggior parte degli usi "di buon senso" delle variabili static const int senza richiedere una definizione. Tuttavia, i casi d'angolo possono essere diversi, tuttavia, molti ritengono che sia meglio usare semplicemente l'anonimo enum, per il quale tutto è cristallino e non c'è alcuna ambiguità.

+1

Hmm, gcc non si lamenta nemmeno con -pedantic -Wall -Wextra. Suppongo che, poiché non è in grado di rilevare l'errore fino al momento del collegamento, rinuncia solo a cercare di diagnosticare codice non portatile di questo tipo. –

+0

Buona risposta. Un'altra cosa carina che non si menziona esplicitamente è che un enum è un valore, e quindi nessuna memoria viene mai assegnata per questo. Può essere utile sapere che * di sicuro *, piuttosto che basarsi sull'ottimizzazione del compilatore se si sta eseguendo metaprogrammazione di modelli e istanziando un gran numero di modelli di classi. – jalf

+1

Se non esiste una definizione per 'static const int' al di fuori della classe, non ci sarà alcuna memoria allocata per quello. Inoltre, i valori rval possono avere una memoria allocata per loro (i valori temporali sono rvalue, per esempio, e usano sicuramente lo spazio di archiviazione). –

-2

linea di fondo - utilizzare const.

più

dettagli:

io non sono un esperto di C++, ma questo sembra una domanda più generale disegno.

Se non è obbligatorio, e si pensa che ci sia una probabilità molto bassa/inesistente che l'enumerazione cresca per avere più di un valore, quindi utilizzare un const regolare. anche se hai torto e ad un certo punto in futuro ci saranno più valori, facendo di un enum la scelta giusta - un semplice refactoring e tu cambierai a enum.

+0

Non si tratta di 'enum' vs' const' dal punto di vista del design di alto livello. Questo è tutto sulle stranezze di C++ in relazione a ogni costrutto. La risposta ovvia è sbagliata qui. –

3

Penso che non ci sia alcun motivo per usare un enum, e che sia effettivamente meglio usare uno static const int per questo scopo, dal momento che un enum ha il suo tipo (anche se implicitamente convertibile in un intero).

+0

Non che mi dispiaccia essere downvoted, ma sarebbe bello farmi sapere perché. Grazie. –

+3

Perché è male che un enum abbia un suo tipo? Il tuo programma ha una quota di tipo che non puoi superare? –

+0

Accettando con @Rob Kennedy. La forte tipizzazione delle costanti è il ** punto ** delle enumerazioni. –

9

La definizione delle costanti statiche direttamente nella definizione di classe è un'aggiunta successiva a C++ e molti continuano ad attenersi alla soluzione alternativa più vecchia di utilizzare uno enum per quello. Potrebbero persino esserci ancora alcuni vecchi compilatori in uso che non supportano le costanti statiche definite direttamente nelle definizioni di classe.

+2

Alcuni compilatori non sempre incorporano il const statico int, mentre l'enum sarà sempre in linea AFAIK. –

5

Nel tuo caso, utilizzerei anche una costante. Tuttavia, vi sono altri casi in cui I potrebbe aggiungere costanti correlate. Come questo:

const int TextFile = 1; // XXX Maybe add other constants for binary files etc.? 

In questi casi, io uso un enum subito con un singolo valore, come questo:

enum FileType { 
    TextFile = 1 
    // XXX Maybe add other values for binary files etc.? 
} 

il motivo è che il compilatore può quindi emettere avvisi quando sto usando il valore costante nelle espressioni degli interruttori, come in:

FileType type; 
// ... 
switch (type) { 
    case TextFile: 
     // ... 
} 

nel caso in cui decido di aggiungere un altro valore costante che è legato al valore esistente (un altro tipo di file, in questo esempio), praticamente tutti i compilatori wil Rilascio un avviso poiché il nuovo valore non è gestito nell'istruzione switch.

Se avessi usato invece "int" e costanti, il compilatore non avrebbe avuto la possibilità di emettere avvisi.

5

L'unico motivo per utilizzare "enum hack" è che i vecchi compilatori non supportano le definizioni const in-class, come dici nella tua domanda.Quindi, a meno che non si sospetti che il tuo codice verrà portato su un vecchio compilatore, dovresti usare const dove const è dovuto.

1

Bene, la portabilità è una buona ragione per utilizzare enum. È fantastico, perché non devi preoccuparti se il tuo compilatore supporta "stat const const S = 10" o no ...

Inoltre, per quanto mi ricordo, la variabile statica deve essere definita da qualche parte, anche come dichiarato, e il valore enum deve essere dichiarato solo.

+0

Un valore 'const const 'di tipo integrale non deve essere definito se la dichiarazione include un inizializzatore di espressioni costanti integrali, ma le regole sono molto confuse. Vedi la mia risposta. –

5

L'uso di enum ha un vantaggio. Un tipo enum è un tipo, quindi se si definisce, per esempio:

enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... }; 

e si dispone di una funzione come:

void Function1(EnumType Value) 

i controlli del compilatore che si sta passando un membro del EnumType enum a la funzione, quindi solo i valori validi per il parametro Valore sarebbero EnumValue1 e EnumValue2. Se si utilizzano le costanti e modificare la funzione di

void Function1(int Value) 

i controlli del compilatore che si sta passando un int (int qualsiasi, una costante, variabile o letterale) alla funzione.

I tipi di enum sono validi per il raggruppamento di valori cost relativi. Per un solo valore const, non vedo alcun vantaggio.

2

C'è una differenza tra questi due. Le enumerazioni non hanno un indirizzo per quanto ne so. tuttavia, fanno sempre intro statiche. Quindi se qualcuno prende l'indirizzo di const static int, cancella il const, può modificare il valore (sebbene il compilatore possa ignorare il cambiamento perché pensa che sia const). Questo è ovviamente puro male e non dovresti farlo - ma il compilatore non può impedirlo. Questo non può accadere con le enumerazioni.

E, naturalmente, se per qualche motivo è necessario l'indirizzo di tale const, è necessario il const statico int.

In breve: enum è un valore massimo mentre const static int è un lvalue. Vedi http://www.embedded.com/story/OEG20011129S0065 per maggiori dettagli.

+0

Il client non sarà in grado di prendere l'indirizzo di una variabile membro 'const const const 'senza una definizione. La distinzione Rvalue/lvalue è azzeccata. –

+0

Il client non lo farà, ma chiunque manterrà la classe e aggiungerà il codice in seguito. –

Problemi correlati