2014-09-30 10 views
11

Większość czasu widzę stałej c-strings zdefiniowane jako:Prawidłowy sposób definiowania stałego ciągu C w C++?

static char const* MY_CONSTANT = "Hello World"; 

Jednak sama wskaźnik nie jest const. Czy nie byłoby lepiej zrobić to jak poniżej?

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

Istnieją 2 bramek ze stałych globalnych, takich jak ten, myślę:

  1. Nie dopuszczać modyfikacja łańcucha
  2. Nie dopuszczać zmienna zwrócić do niczego innego

Po prostu założyłem, że te 2 cele były potrzebne przy definiowaniu stałych ciągów.

Inną ciekawą rzeczą jest to, że mam do tego prawo:

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

Ten mówi mi, że auto dedukuje ciąg jako char const* i nie char const* const.

Mam więc dwa główne pytania:

  1. Co jest najwłaściwszym sposobem definiowania stałych ciągów stylu C (przypuszczam stale wskaźniki do czegoś, jest bardziej ogólne pytanie?). Dlaczego wybierasz jeden lub drugi?
  2. Jeśli chodzi o mój przykład z auto, to ma sens, dlaczego wybiera char const* (ponieważ jest to tablica danych, która jest stała, a nie sam wskaźnik). Czy mogę dokonać auto wywnioskować na char const* const lub czy mogę zmienić kod, aby uzyskać taki typ?
+0

Nie znaczy 'const char * const'? – Adam

+4

@Adam Oba formularze są poprawne C++. Twój robi to samo co moje. –

+1

Domyślnie "auto" wykrywa minimalne ograniczenie, co oznacza, że ​​fakt, że zmienna nie może być ponownie przypisana, jest tylko twoim wyborem. możesz zrobić "auto const", jak sądzę, jeśli chcesz, ale najlepiej nie narzucać go wszystkim. –

Odpowiedz

6

Dobrze, jeśli on rzeczywiście stała wtedy constexpr byłoby C++ 11 sposobem, aby to zrobić:

constexpr char const* MY_CONSTANT = "Hello World"; 

Pierwszy przykład:

static char const* MY_CONSTANT = "Hello World"; 

prostu mówi mi mieć wskaźnik do stałej char, która ma statyczny czas przechowywania, który, jeśli znajduje się poza funkcją, uczyniłby ją globalną.

Jeśli potrzebujemy, aby wskaźnik również był const, potrzebujemy drugiej formy, którą wprowadziłeś. Wszystko zależy od tego, czy wskaźnik rzeczywiście ma być stały, czy nie. W większości przypadków powodem, dla którego widzisz kod bez konstelacji najwyższego poziomu, jest to, że po prostu zapomniały go wstawić, ponieważ nie znaczyły, że wskaźnik również jest stały.

Gdzie statyczny robi różnicę na przykład jeśli czy chcesz const member aby być per-instancji lub per-Klasa:

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

Jeśli wymagają const być per-klasy następnie musimy użyć static w przeciwnym razie nie.Przykład zmienia się nieznacznie, jeśli nie wolno używać 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" ; 

ale istota jest taka sama tylko składnia jest inna.

Za drugie pytanie, Gotw #92 mówi auto spada top const poziomie, jeden przykład podany jest w sposób następujący:

const int ci = val; 
auto  g = ci; 

i mówi:

Rodzaj g int.

Pamiętaj, tylko dlatego, że ci jest const (tylko do odczytu), nie ma żadnego wpływającego na to, czy chcemy, aby g było const. To osobna zmienna. Jeśli chcieliśmy g być const, chcielibyśmy powiedzieć const auto jak to miało miejsce w przypadku c powyżej

przykład, że jest mowa jest w następujący sposób:

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

Niestety constexpr nie jest obsługiwana w MSVC 12 :-( –

+0

@ void.pointer nie trzeba * constexpr * odpowiedź nie zmienia tylko składnię. I uaktualniony odpowiedź na to przykład bez * constexpr *, jak również. –

0

Jest to rzadki przypadek gdzie zdarza się, że robisz nadpisać wskaźnik, który wskazuje na wartość const, zatem większość deweloperów pominąć drugą const ale semantycznie byłoby rzeczywiście poprawne w ten sposób:

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

czy w tej formie:

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

constexpr dla deklaracji jest po prostu potrzebne, jeśli jest częścią innej funkcji constexpr jak ten:

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 ma typ const char (&)[12]
  • Brak zaniku (granica tablic nie jest tracona)
  • Wszystko jest Stała - sama tablica i odniesienia (z definicji)
  • Wszystko constexpr (może być stosowany w czasie kompilacji) - sama tablica a odniesienie
  • MY_CONSTANT posiada wewnętrzne połączenie powodu constexpr i mogą być wykorzystane w nagłówku
+0

Z VC++ 'static auto & MY_CONSTANT =" Hello World ";' może być użyty zamiast tego: – user2665887

+0

'static' nie ma nic wspólnego ze stałością.Oznacza to, że funkcja nie jest widoczna w innych jednostkach kompilacji. –

0

Dobrze zrobione, aby zauważyć const na części wskaźnika! Wiele osób nie zdaje sobie z tego sprawy.

Aby zapobiec powielaniu literału ciągu znaków na jednostkę tłumaczeniową (lub ułatwić część pulsującego optymalizator), sugeruję umieszczenie rzeczywistych danych w pliku źródłowym. To również zapisze trochę rekompilacji, jeśli zmienisz tekst.

Header:

extern const char *const mystring;

źródło:

extern const char *const mystring = "hello";

Alternatywnie

Header:

extern const std::string mystring;

źródło:

extern std::string mystring = "hello";

Powiązane problemy