Co to jest string_view?

162

string_viewbył proponowaną funkcją w C ++ Library Fundamentals TS ( N3921 ) dodanym do C ++ 17

O ile rozumiem, jest to typ, który reprezentuje pewnego rodzaju „koncepcję” ciągu, czyli widok dowolnego typu kontenera, który może przechowywać coś, co można zobaczyć jako ciąg.

  • Czy to jest poprawne ?
  • Czy const std::string&typ parametru kanonicznego powinien stać się string_view?
  • Czy jest jeszcze jedna ważna kwestia, którą string_viewnależy wziąć pod uwagę?
Drax
źródło
4
Wreszcie ktoś zdaje sobie sprawę, że ciągi znaków wymagają innej semantyki, chociaż wprowadzenie string_view to tylko mały krok.
John Z. Li

Odpowiedzi:

183

Celem wszelkich propozycji „odwołań do ciągów znaków” i „odwołań do tablicy” jest uniknięcie kopiowania danych, które są już w innym miejscu posiadane i dla których wymagany jest tylko niezmutowany widok. Chodzi string_viewo jedną z takich propozycji; były też wcześniej zwane string_refi array_ref.

Chodzi o to, aby zawsze przechowywać parę wskaźników do pierwszego elementu i rozmiar jakiejś istniejącej tablicy lub ciągu danych.

Taka klasa uchwytu widoku mogłaby być tanio przekazywana według wartości i oferowałaby tanie operacje na podciągach (które można zaimplementować jako proste przyrosty wskaźnika i dostosowania rozmiaru).

Wiele zastosowań łańcuchów nie wymaga faktycznego posiadania łańcuchów, a dany ciąg często będzie już własnością kogoś innego. Istnieje więc prawdziwy potencjał zwiększenia wydajności poprzez unikanie niepotrzebnych kopii (pomyśl o wszystkich przydziałach i wyjątkach, które możesz zaoszczędzić).

Oryginalne ciągi C cierpiały na problem polegający na tym, że terminator zerowy był częścią interfejsów API ciągów, więc nie można było łatwo tworzyć podciągów bez mutowania podstawowego ciągu (a la strtok). W C ++ można to łatwo rozwiązać, przechowując osobno długość i zawijając wskaźnik i rozmiar w jedną klasę.

Jedyną główną przeszkodą i rozbieżnością w stosunku do standardowej filozofii biblioteki C ++, o której mogę pomyśleć, jest to, że takie klasy „widoku referencyjnego” mają zupełnie inną semantykę własności niż reszta biblioteki standardowej. Zasadniczo wszystko inne w bibliotece standardowej jest bezwarunkowo bezpieczne i poprawne (jeśli się kompiluje, jest poprawne). W przypadku takich klas referencyjnych nie jest to już prawdą. Poprawność programu zależy od kodu otoczenia, który używa tych klas. Więc trudniej to sprawdzić i uczyć.

Kerrek SB
źródło
19
Statek płynął zgodnie z tą filozofią reference_wrapper, prawda?
Steve Jessop,
5
@KerrekSB Obawiam się, że nie śledzę. Czy mógłbyś rozwinąć część „takie klasy widoków referencyjnych mają zupełnie inną semantykę własności niż reszta standardowej biblioteki” ? Nie jest dla mnie jasne: czym różni się od wiszących odniesień / wskazówek? Lub unieważnione iteratory z powodu wstawienia (np. Std :: vector)? Już mamy te problemy, jest dla mnie bardzo naturalne, że pogląd nie będący właścicielem będzie miał podobne problemy, jak mają wskaźniki / odniesienia / iteratory niebędące właścicielami.
Ali
5
@Ali: Kiedy używasz dowolnego innego kontenera biblioteki standardowej, możesz potwierdzić poprawność kodu, po prostu patrząc na kod, który używa kontenera. Nie tak string_view. (Nie mówiłem, że nigdy nie możesz pisać zepsutego kodu. Tylko, że zepsuty jest lokalny .)
Kerrek SB
6
Jestem zaskoczony, że nie poszli z std::rangeod boost::iterator_range- IMO jest lepsze niż pomysł string_view
Charles Salvia
19
@nwp: Wiele osób i języków lamentuje nad okropnymi domyślnymi ustawieniami C ++ i uważa, że ​​wartości domyślne to „const” i „unshared”, z „mutable” i „shared” w wyraźnych, rzadkich wyjątkach.
Kerrek SB