Wenn ich http://en.cppreference.com/w/cpp/string/basic_string_view als Referenz verwende, sehe ich keine Möglichkeit, dies eleganter zu tun:
std::string s = "hello world!";
std::string_view v = s;
v = v.substr(6, 5); // "world"
Schlimmer noch, der naive Ansatz ist eine Falle und hinterlässt v
einen baumelnden Hinweis auf eine vorübergehende:
std::string s = "hello world!";
std::string_view v(s.substr(6, 5)); // OOPS!
Ich erinnere mich an so etwas wie einen Zusatz zur Standardbibliothek, um einen Teilstring als Ansicht zurückzugeben:
auto v(s.substr_view(6, 5));
Ich kann mir folgende Problemumgehungen vorstellen:
std::string_view(s).substr(6, 5);
std::string_view(s.data()+6, 5);
// or even "worse":
std::string_view(s).remove_prefix(6).remove_suffix(1);
Ehrlich gesagt finde ich keines davon sehr nett. Im Moment ist das Beste, was ich mir vorstellen kann, Aliase zu verwenden, um die Dinge einfach weniger ausführlich zu machen.
using sv = std::string_view;
sv(s).substr(6, 5);
string_view(s).substr(...)
), scheint besser zu sein als eine einzelne Funktion, die zwei Dinge gleichzeitig.substr_view(...)
ausführt ( ), selbst wenn sie existiert.std::string::substr
sollstd::string_view
?std::basic_string<>
Benutzeroberfläche, diesubtr_view
tatsächlich eine Operation wie hinzufügen würden . Das habe ich in der Frage erwähnt. Ich hatte gehofft, jemand würde antworten und sagen "Das ist Vorschlag Nxxxx, der abgelehnt / in C ++ zz oder TSn akzeptiert wurde"std::string_view::substr()
bricht die Methode ihre eigenen Regeln, da sie eine string_view zurückgibt. Ich denke also, der Rat wäre, dies niemals zu tun. Verwenden Sie astd::string
.Antworten:
Es gibt die Route mit freien Funktionen, aber es sei denn, Sie stellen auch Überladungen für
std::string
eine Schlangengrube bereit .#include <string> #include <string_view> std::string_view sub_string( std::string_view s, std::size_t p, std::size_t n = std::string_view::npos) { return s.substr(p, n); } int main() { using namespace std::literals; auto source = "foobar"s; // this is fine and elegant... auto bar = sub_string(source, 3); // but uh-oh... bar = sub_string("foobar"s, 3); }
IMHO ist das gesamte Design von string_view eine Horrorshow, die uns zurück in eine Welt voller Segfaults und verärgerter Kunden führt.
aktualisieren:
Sogar das Hinzufügen von Überladungen für
std::string
ist eine Horrorshow. Sehen Sie, ob Sie die subtile Segfault-Zeitbombe erkennen können ...#include <string> #include <string_view> std::string_view sub_string(std::string_view s, std::size_t p, std::size_t n = std::string_view::npos) { return s.substr(p, n); } std::string sub_string(std::string&& s, std::size_t p, std::size_t n = std::string::npos) { return s.substr(p, n); } std::string sub_string(std::string const& s, std::size_t p, std::size_t n = std::string::npos) { return s.substr(p, n); } int main() { using namespace std::literals; auto source = "foobar"s; auto bar = sub_string(std::string_view(source), 3); // but uh-oh... bar = sub_string("foobar"s, 3); }
Der Compiler hat hier nichts zu warnen gefunden. Ich bin mir sicher, dass eine Codeüberprüfung dies auch nicht tun würde.
Ich habe es schon einmal gesagt und ich werde es noch einmal sagen, falls jemand im c ++ - Komitee zuschaut, ist das Zulassen impliziter Konvertierungen von
std::string
nachstd::string_view
ein schrecklicher Fehler, der nur dazu dient, c ++ in Verruf zu bringen .Aktualisieren
Nachdem ich diese (für mich) ziemlich alarmierende Eigenschaft von string_view im cpporg-Message Board angesprochen habe, wurden meine Bedenken mit Gleichgültigkeit beantwortet.
Der Konsens der Ratschläge dieser Gruppe ist, dass
std::string_view
niemals von einer Funktion zurückgegeben werden darf, was bedeutet, dass mein erstes Angebot oben eine schlechte Form ist.Es gibt natürlich keine Compiler-Hilfe, um Zeiten zu erfassen, in denen dies versehentlich passiert (zum Beispiel durch Vorlagenerweiterung).
Daher
std::string_view
sollte mit äußerster Sorgfalt vorgegangen werden, da es aus Sicht der Speicherverwaltung einem kopierbaren Zeiger entspricht, der auf den Status eines anderen Objekts zeigt, das möglicherweise nicht mehr vorhanden ist. Im Übrigen sieht es jedoch wie ein Wertetyp aus und verhält sich auch so.Also Code wie folgt:
auto s = get_something().get_suffix();
Ist sicher, wenn
get_suffix()
a zurückgegeben wirdstd::string
(entweder nach Wert oder Referenz)ist aber UB, wenn get_suffix () jemals überarbeitet wird, um a zurückzugeben
std::string_view
.Was meiner bescheidenen Ansicht nach bedeutet, dass jeder Benutzercode, in dem zurückgegebene Zeichenfolgen
auto
gespeichert sind, beschädigt wird, wenn die von ihnen aufgerufenen Bibliotheken jemals überarbeitet werden, umstd::string_view
anstelle von zurückgegeben zu werdenstd::string const&
.Zumindest für mich muss "fast immer automatisch" von nun an "fast immer automatisch" werden, außer wenn es sich um Zeichenfolgen handelt.
quelle
string foo(); bool bar(string_view); auto check = bar(foo());
ist sicher und vernünftig zuzulassen.bar
ist einestring_view
Konstruktion aus einerstring_view
Konstruktion aus einer temporärenstd::string
, die jetzt zerstört wurde.Sie können den Konvertierungsoperator von std :: string nach std :: string_view verwenden :
std::string s = "hello world!"; std::string_view v = std::string_view(s).substr(6, 5);
quelle
v
er auf einen temporären Puffer verweist, der sofort ungültig wird.Auf diese Weise können Sie effizient eine Unterzeichenfolge string_view erstellen.
#include <string> inline std::string_view substr_view(const std::string &s,size_t from,size_t len) { if( from>=s.size() ) return {}; return std::string_view(s.data()+from,std::min(s.size()-from,len)); } #include <iostream> int main(void) { std::cout << substr_view("abcd",3,11) << "\n"; std::string s {"0123456789"}; std::cout << substr_view(s,3,2) << "\n"; // be cautious about lifetime, as illustrated at https://en.cppreference.com/w/cpp/string/basic_string_view std::string_view bad = substr_view("0123456789"s, 3, 2); // "bad" holds a dangling pointer std::cout << bad << "\n"; // possible access violation return 0; }
quelle