2009-01-20 17 views
40

Widziałem kod z tymi dwoma stylami, nie jestem pewien, czy jeden jest lepszy od drugiego (czy to tylko kwestia stylu)? Czy masz jakieś zalecenia, dlaczego wybrałbyś jedną z drugą.Definiowanie stałych ciągów znaków w C++?

//Example1 
class Test { 

    private: 
     static const char* const str; 

}; 

const char* const Test::str = "mystr"; 

//Example2 
class Test { 

    private: 
     static const std::string str; 

}; 

const std::string Test::str ="mystr"; 
+1

jak to przeszkadza? –

Odpowiedz

55

Zwykle powinieneś preferować std::string nad prostymi znakami char. Tutaj jednak wskaźnik znakowy zainicjalizowany literałem łańcuchowym ma znaczną korzyść.

Istnieją dwie inicjalizacje dla danych statycznych. Ten nazywa się inicjalizacją statyczną, a drugi nazywa się inicjalizacją dynamiczną. W przypadku obiektów zainicjalizowanych za pomocą wyrażeń stałych oraz POD (takich jak wskaźniki), C++ wymaga, aby ich inicjalizacja odbywała się na samym początku, zanim nastąpi inicjalizacja dynamiczna. Inicjowanie takiego std :: string będzie wykonywane dynamicznie.

Jeśli obiekt klasy jest statycznym obiektem w jakimś pliku, a ten musi uzyskać dostęp do ciągu znaków podczas jego inicjowania, możesz polegać na tym, że jest on już skonfigurowany, gdy używasz wersji const char* const, podczas gdy używając wersji std::string, która nie jest zainicjalizowana statycznie, nie wiadomo, czy łańcuch znaków jest już zainicjowany - ponieważ kolejność inicjowania obiektów przez granice jednostki tłumaczeniowej nie jest zdefiniowana.

+7

+1 Spędziłem czas na debugowaniu bardzo nieprzyjemnych awarii, które okazały się spowodowane przez statyczne instancje klasy łańcuchowej, która zepsuła się z powodu problemów z kolejnością inicjowania. Unikaj statycznych instancji 'std :: string'! –

+1

Byłem bardzo zaskoczony tą odpowiedzią. Czy jest jakiś sposób, aby działał z std :: string? – loop

+0

@ test: yes: 'std :: string const i safe_string_const() {std :: string static const var =" const "; return var; } ' –

4

Hmmm, std :: string nie jest taki sam jak const char *. Zazwyczaj błędnie używam std :: string, ponieważ jest to klasa, która ma wiele dodatkowych możliwości, które znacznie ułatwiają korzystanie.

Jeśli wydajność jest najważniejsza i używasz const char * dla wydajności, idź tą drogą.

2

Pierwszy przykład wymaga mniej narzutów do zarządzania ciągiem znaków (tj. Tylko wskaźnikiem do sekcji TEKST). Druga metoda może również wymagać alokacji sterty, a także skopiowania literału łańcuchowego do bufora klasy std: string. Tak więc skończyłbyś z dwiema kopiami danych.

1

Druga wersja ma tę zaletę, że ma wstępnie obliczoną długość i inne zalety klasy z wyostrzonymi ciągami. Pierwsza ma tę zaletę, że jedyną inicjalizacją jest właśnie przypisanie wskaźnika do statycznych danych już załadowanych do pliku wykonywalnego, gdzie drugi musi zainicjować ciąg z tego samego wskaźnika.

+0

Pierwsza wersja ma strlen ... –

+0

Tak, ale jest to operacja O (n), więc w zależności od użycia może to być problem. – Eclipse

+0

Ale przypuszczam, że to tylko debata na temat korzyści std :: string vs char * w ogóle. – Eclipse

3

Zwykle preferuję std :: string over char * przy wykonywaniu C++. Preferuję std :: string głównie ze względu na jego wbudowane możliwości, a także wygodę i bezpieczeństwo bez konieczności radzenia sobie ze wskaźnikami.

Jednak, jak wspomnieli inni, wersja const char * może być korzystna, jeśli jesteś zbytnio zaniepokojony wydajnością. Przypominam sobie, że ktoś mądry kiedyś stwierdził, że przedwczesna optymalizacja jest źródłem wszelkiego zła (lub niektórych takich). :)

2

W dużych projektach obejmujących kilka platform z różnymi kompilatorami i bibliotekami, wiele zespołów i wiele osób wielokrotnie natknęliśmy się na problemy ze statycznymi std :: stringami. Na niektórych platformach implementacja std: string nie jest bezpieczna dla wątków. Na jednej platformie zoptymalizowany kod kompilatora pomijał inicjowanie lokalnego std: string z globalnej stałej statycznej. Po wyprowadzeniu kilku z tych problemów dopuszczamy tylko globalne statyczne const dla wbudowanych typów.

1

Po pierwsze, jeśli nie użyłby znaku *.Jeśli chcesz ciąg ASCIIZ zdefiniować jeden z nich bezpośrednio:

const char Test::str[] = "mystr";

W przeważającej części, to co bym użyć. Po co marnować czas i pamięć na obciążenie klasy string.

Zauważ, że "sizeof (Test :: str)" dokładnie da ci długość tablicy, która jest długością struny, łącznie z kończącym NUL (strlen (str) +1).

+0

Trochę dziwne stwierdzenie, że std :: string marnuje pamięć, gdy tracisz sizeof (Test :: str) przez kopiowanie bardzo dobry const char [] dla innego const char []. – MSalters

+0

Kto coś kopiuje? Czy "const int x = 5;" kopiowanie czegokolwiek? Jest tylko jeden znak [], który z natury posiada wartość "mystr"; –