Jakieś gotcha zastępujące globalną const char [] constexpr string_view?


17

Nasz zespół pracuje z ponad 10-letnią bazą kodu C ++, a ostatnio przeszedł na kompilator C ++ 17. Szukamy więc sposobów modernizacji naszego kodu. Podczas konferencji na YouTube usłyszałem sugestię zastąpienia const char*globalnych ciągów constexpr string_view.

Ponieważ const char*w naszym kodzie mamy całkiem sporo takich globalnych stałych ciągów, chcę zapytać, czy są jakieś problemy lub potencjalne problemy, o których musimy wiedzieć?

Odpowiedzi:


15

Warto zwrócić uwagę na następujące problemy:

  1. std::string_viewnie trzeba go nullzabijać. Więc jeśli zastąpić niektóre const char*przez string_viewi wymienić budowę wcześniej null-zakończony char*podciąg przez string_viewpośrednictwem std::string_view::substr, nie można przekazać wskaźnika stanowiącego podstawę do API, która oczekuje null-zakończony ciąg. Przykład (bez UB, ale również łatwy do zbudowania):

    void legacy(const char *str) {
       std::printf("%s\n", str);
    }
    
    constexpr std::string_view sv1 = "abcde";
    constexpr std::string_view sv2 = sv1.substr(0, 2); // view on "ab"
    
    legacy(sv2.data()); // Not intended: prints "abcde" 
  2. Chociaż możesz niejawnie zbudować std::stringz const char*, nie możesz tego zrobić za pomocą std::string_view. Chodzi o to, że głęboka kopia nie powinna się zdarzyć pod przykryciem, ale tylko na wyraźne życzenie. Przykład:

    std::map<std::string, int> m;
    constexpr std::string_view sv = "somekey";
    constexpr const char *old = "somekey";
    
    m[old] = 42; // works as expected
    m[sv] = 42; // fails to compile
    m[std::string(sv)] = 42; // be explicit, this is ok

    W zależności od istniejącego użycia globalnych const char*instancji w projekcie, to zachowanie może wymagać ręcznej interwencji w różnych miejscach.


że niezerowe zakończenie jest zdecydowanie gotcha - auch. Teraz muszę przejrzeć nasze SV. Podejrzewam, że zrobiłbyś std::string(sv).c_str()zamiast tego przejść do API?
darune

@darune To jest opcja, ale wtedy należy sprawdzić założenia API na całe życie, prawda ?! Jeśli pójdziesz someLegacyFct(std::string(sv).c_str())i ten backend jakoś przechowuje wskaźnik ...
lubgr

to jest poprawne - tylko przy takim założeniu na całe życie
darune

Druga kwestia to „na szczęście” nie będzie to dla nas wielka sprawa. Struktura naszej firmy ma własną klasę ciągów (wiem ...), z wyraźnym const char*konstruktorem. Tak wyraźna konstrukcja std::stringz string_viewbyłaby w naszym przypadku po prostu spójna.
PixelSupreme,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.