2014-09-30 8 views
11

Die meiste Zeit sehe ich konstant C-Strings wie folgt definiert:Korrekter Weg, um eine konstante C-Zeichenfolge in C++ zu definieren?

static char const* MY_CONSTANT = "Hello World"; 

jedoch der Zeiger selbst ist nicht const. Wäre es nicht angemessener, es wie unten zu tun?

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

Es gibt zwei Ziele mit konstanten Globals wie diese, denke ich:

  1. nicht zulassen Änderung der Zeichenfolge
  2. Sie die Variable auf etwas anderen
nicht zulassen, dass Punkt

Ich nahm einfach an, dass diese 2 Ziele bei der Definition konstanter Strings benötigt wurden.

Eine weitere interessante Sache ist, dass ich dies zu tun bin erlaubt:

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

Das sagt mir, dass auto die Zeichenfolge als char const* und nicht char const* const folgert. Ich habe zwei Hauptfragen

So:

  1. Was die am besten geeignete Art und Weise konstant c-Strings zu definieren (ich nehme an konstante Zeiger zu etwas, ist die allgemeinere Frage?). Warum wählst du das eine oder das andere aus?
  2. In Bezug auf mein Beispiel mit auto macht es Sinn, warum wählt char const* (weil es das Array von Daten ist, die konstant ist, nicht der Zeiger selbst). Könnte ich auto auf char const* const ableiten oder kann ich den Code ändern, um einen solchen Typ zu ergeben?
+0

Meinen Sie nicht 'const char * const'? – Adam

+4

@Adam Beide Formen sind gültig C++. Dein tut das gleiche wie meins. –

+1

Der Standardwert, den 'auto' erkennt, ist die minimale Einschränkung, was bedeutet, dass die Tatsache, dass die Variable nicht neu zugewiesen werden kann, nur Ihre Entscheidung ist. du kannst 'auto const' machen, nehme ich an, wenn du willst, aber es ist am besten, es nicht jedem aufzudrängen. –

Antwort

6

Nun, wenn es ein wirklich konstant ein dann constexpr sei die C++ 11 Art und Weise, dies zu tun:

constexpr char const* MY_CONSTANT = "Hello World"; 

Das erste Beispiel:

static char const* MY_CONSTANT = "Hello World"; 

nur sage, ich habe einen Zeiger auf einen char const, der eine statische Speicherdauer hat, was, wenn er außerhalb einer Funktion ist, ihn global machen würde.

Wenn der Zeiger auch const sein soll, brauchen wir die zweite Form, die Sie eingeführt haben. Es kommt darauf an, ob der Zeiger tatsächlich const ist oder nicht. In den meisten Fällen ist der Grund, warum Ihr Code ohne die oberste Ebene const angezeigt wird, weil er vergessen hat, ihn nicht zu setzen, weil er nicht bedeutet, dass der Zeiger auch const ist.

Wo statische einen Unterschied zum Beispiel macht, wenn, ob Sie ein const Mitglied wollen pro-Instanz sein oder pro Klasse:

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

Wenn benötigen wir die const pro-Klasse zu sein, dann Wir müssen statische sonst nicht verwenden.Das Beispiel ändert sich leicht, wenn Sie nicht erlaubt sind constexpr zu verwenden:

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" ; 

aber das Wesentliche ist das gleiche nur die Syntax unterscheidet.

Für Ihre zweite Frage wie Gotw #92 sagt auto ist gegeben Top-Level-const, ein Beispiel fällt wie folgt:

const int ci = val; 
auto  g = ci; 

und es sagt:

Die Art der g int ist.

Denken Sie daran, nur weil ci ist const (schreibgeschützt) hat keine auf, ob wir wollen, dass g const sein. Es ist eine separate Variable. Wenn wir g const sein wollten, hätten wir gesagt: const Auto, wie wir im Fall taten c oben

das Beispiel, das bezeichnet wird, ist wie folgt:

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

Leider wird consExpr auf msvc 12 nicht unterstützt :-( –

+0

@ void.pointer du brauchst * constexpr * nicht die Antwort ändert nicht nur die Syntax. Ich aktualisierte die Antwort, um ein Beispiel ohne * constexpr * auch zu enthalten. –

0

Es ist ein seltener Fall wo es passiert, dass Sie den Mauszeiger überschreiben, die zu einem const Wert weist daher die meisten Entwickler auslassen die zweite const aber semantisch würde es auf diese Weise in der Tat richtig sein:

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

oder in dieser Form:

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

constexpr für die Erklärung nur erforderlich, wenn es Teil einer anderen constexpr Funktion ist wie folgt:

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 hat Typ const char (&)[12]
  • Kein Verfall (die Array-Grenze ist nicht verloren)
  • Alles ist Konstante - das Array selbst und die Referenz (per Definition)
  • Alles ist constexpr (kann bei der Kompilierung verwendet werden) - die Anordnung selbst als auch die Referenz
  • MY_CONSTANT hat interne Bindung aufgrund constexpr und kann
  • in Headern verwendet werden,
+0

Mit VC++ 'static auto & MY_CONSTANT =" Hello World ";' kann stattdessen verwendet werden. – user2665887

+0

'static' hat nichts mit Konstanz zu tun. Das bedeutet, dass die Funktion in anderen Kompilierungseinheiten nicht sichtbar ist. –

0

Gut gemacht, um die const auf dem Zeigerteil zu bemerken! Viele Leute merken das nicht.

Um zu verhindern, dass das Stringliteral pro Übersetzungseinheit dupliziert wird (oder den String-Pooling-Teil des Optimierers vereinfacht), schlage ich vor, die tatsächlichen Daten irgendwo in eine Quelldatei zu schreiben. Dies wird auch einige Neukompilierungen speichern, wenn Sie den Text ändern.

Header:

extern const char *const mystring;

Quelle:

extern const char *const mystring = "hello";

Alternativ

Header:

extern const std::string mystring;

Quelle:

extern std::string mystring = "hello";