2014-09-30 15 views
11

maggior parte del tempo vedo costanti C-stringhe definite come:Modo corretto per definire una costante C-string in C++?

static char const* MY_CONSTANT = "Hello World"; 

Tuttavia, il puntatore in sé non èconst. Non sarebbe più appropriato farlo come sotto?

static char const* const MY_CONSTANT = "Hello World"; 

Ci sono 2 obiettivi con globali costanti come questo, penso:

  1. Non consentire la modifica della stringa
  2. Non consentire la variabile per puntare a qualsiasi altra cosa

Ho semplicemente pensato che questi 2 obiettivi fossero necessari per definire stringhe costanti.

Un'altra cosa interessante è che mi è permesso di fare questo:

int main() 
{ 
    auto MY_CONSTANT = ""; 
    MY_CONSTANT = "Another String"; 
} 

Questo mi dice che auto deduce la stringa come char const* e non char const* const.

Così ho due domande principali:

  1. Qual è il modo più appropriato per definire costanti stringhe c-style (suppongo costanti puntatori a qualcosa, è la questione più generale?). Perché scegli l'una o l'altra?
  2. Per quanto riguarda il mio esempio con auto, ha senso perché sceglie char const* (perché è la matrice di dati che è costante, non il puntatore stesso). Posso fare auto dedurre a char const* const o posso cambiare il codice per farlo risultare in tale tipo?
+0

Non si vuol dire 'const char * const'? – Adam

+4

@Adam Entrambi i moduli sono C++ validi. La tua fa la stessa cosa della mia. –

+1

il valore predefinito che "auto" rileva è la restrizione minima, il che significa che il fatto che la variabile non possa essere riassegnata è solo una tua scelta. puoi fare 'auto const' suppongo, se vuoi, ma è meglio non imporlo a tutti. –

risposta

6

Beh, se un vero e proprio una costante allora constexpr sarebbe il modo C++ 11 per fare questo:

constexpr char const* MY_CONSTANT = "Hello World"; 

Il primo esempio:

static char const* MY_CONSTANT = "Hello World"; 

dice solo che avere un puntatore a un char const che ha una durata di archiviazione statica, che se è al di fuori di una funzione lo renderebbe globale.

Se è necessario che il puntatore sia const, è necessario il secondo modulo introdotto. Tutto dipende dal fatto che il puntatore debba effettivamente essere const o no. Nella maggior parte dei casi, il motivo per cui il codice di visualizzazione senza il const di livello superiore è perché si sono semplicemente dimenticati di inserirlo non perché non intendevano il puntatore essere anche const.

Dove statica fa la differenza per esempio se se si desidera un const membro di essere per-istanza o per-classe:

class A 
{ 
     char const* const const_per_instance = "Other Const String"; 
    public: 
     constexpr static char const* const const_per_class = "Hello World" ; 
}; 

Se si richiede la const essere per-class poi abbiamo bisogno di usare statico altrimenti no.L'esempio cambia leggermente se non si è autorizzati a utilizzare constexpr:

class A 
{ 
     char const* const const_per_instance = "Other Const String"; 
    public: 
     static char const* const const_per_class ; 
}; 

char const* const A::const_per_class = "Hello World" ; 

ma la sostanza è la stessa solo la sintassi è diversa.

riguarda la seconda domanda, come dice Gotw #92 auto scende const livello più alto, un esempio dato è la seguente:

const int ci = val; 
auto  g = ci; 

e dice:

Il tipo di g è int.

Ricordate, solo perché ci è const (sola lettura) non ha alcun relativo al fatto che vogliamo che g sia const. È una variabile separata. Se volevamo g di essere const, avremmo detto auto const come abbiamo fatto nel caso in cui c sopra

l'esempio che viene indicato è la seguente:

int   val = 0; 
//.. 
const auto c = val; 
+1

Purtroppo constexpr non è supportato su msvc 12 :-( –

+0

@ void.pointer non è necessario * constexpr * la risposta non cambia solo la sintassi.Ho aggiornato la risposta per includere un esempio senza * constexpr * pure –

0

Si tratta di un caso raro dove capita che fate sovrascrivere il puntatore che indica un valore const, quindi la maggior parte gli sviluppatori di omettere il secondo const ma semanticamente sarebbe infatti corretto in questo modo:

static char const* const MY_CONSTANT = "Hello World"; 

o in questa forma:

static const char* const MY_CONSTANT = "Hello World"; 

constexpr per la dichiarazione solo è necessario se fa parte di un'altra funzione constexpr simili:

static constexpr const char* const MY_CONSTANT = "Hello World"; 
static constexpr const char* Foo() 
{ 
    // ... 
    return MY_CONSTANT; 
} 
2
constexpr auto& MY_CONSTANT = "Hello World"; 
  • MY_CONSTANT ha tipo const char (&)[12]
  • Nessun decadimento (l'array vincolato non viene perso)
  • Tutto è in ordine costante - la matrice stessa e il riferimento (per definizione)
  • Tutto è constexpr (può essere utilizzato al momento della compilazione) - la matrice stessa e il riferimento
  • MY_CONSTANT ha il collegamento interno a causa constexpr e può essere utilizzato nelle intestazioni
+0

Con VC++ 'static auto e MY_CONSTANT =" Hello World ";' possibile usare invece ' – user2665887

+0

' static' non ha nulla a che fare con costanza, significa che la funzione non è visibile in altre unità di compilazione. –

0

Complimenti per aver notato la costante sulla parte puntatore! Molte persone non si rendono conto di quel po '.

Per evitare che il valore letterale della stringa venga duplicato per unità di traduzione (o semplificare la parte di ottimizzazione del pool di stringhe dell'ottimizzatore), suggerisco di inserire i dati effettivi in ​​un file sorgente da qualche parte. Questo salverà anche qualche ricompilazione se cambi il testo.

intestazione:

extern const char *const mystring;

fonte:

extern const char *const mystring = "hello";

alternativa

intestazione:

extern const std::string mystring;

fonte:

extern std::string mystring = "hello";