web-dev-qa-db-de.com

So erhalten Sie effizient einen `string_view` für einen Teilstring von` std :: string`

Wenn Sie http://en.cppreference.com/w/cpp/string/basic_string_view als Referenz verwenden, 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 schwankenden Hinweis auf eine temporäre:

std::string s = "hello world!";
std::string_view v(s.substr(6, 5)); // OOPS!

Ich scheint sich zu erinnern Etwas wie die Standardbibliothek könnte hinzugefügt werden, um einen Teilstring als Ansicht zurückzugeben:

auto v(s.substr_view(6, 5));

Ich kann mir die folgenden 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, ich glaube nicht, dass irgendetwas davon sehr nett ist. 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);
57
sehe

Es gibt die Free-Function-Route, aber wenn Sie nicht auch Überlastungen für std::string bereitstellen, ist dies eine Schlangengrube.

#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 wütender Kunden führt.

aktualisieren:

Selbst das Hinzufügen von Überladungen für std::string ist eine Horrorshow. Sehen Sie, ob Sie die subtile Zeitverzögerung von Segfault 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. Ich bin mir sicher, dass eine Überprüfung des Codes auch nicht erfolgen würde.

Ich habe es schon gesagt und ich sage es noch einmal, falls jemand im C++ - Komitee zusieht, implizite Konvertierungen von std::string in std::string_view zuzulassen, ist ein schrecklicher Fehler, der nur dazu dient, c ++ in Verruf zu bringen .

Aktualisieren

Nachdem ich diese (für mich) eher alarmierende Eigenschaft von string_view im cpporg Message Board angesprochen hatte, sind meine Bedenken auf Gleichgültigkeit gestoßen.

Der Konsens der Ratschläge dieser Gruppe ist, dass std::string_view niemals von einer Funktion zurückgegeben werden muss, was bedeutet, dass mein erstes Angebot oben eine schlechte Form ist.

Es gibt natürlich keine Compiler-Hilfe, um Zeiten abzufangen, wenn dies versehentlich geschieht (z. B. durch Vorlagenerweiterung).

Daher sollte std::string_view mit äußerster Sorgfalt verwendet werden, da er aus Sicht der Speicherverwaltung einem kopierbaren Zeiger entspricht, der auf den Status eines anderen Objekts verweist, das möglicherweise nicht mehr vorhanden ist. Im übrigen sieht es jedoch anders aus und verhält sich wie ein Werttyp.

Also Code wie folgt:

auto s = get_something().get_suffix();

Ist sicher, wenn get_suffix() einen std::string zurückgibt (entweder nach Wert oder als Referenz).

ist aber UB, wenn get_suffix () jemals umgestaltet wird, um einen std::string_view zurückzugeben.

Was in meiner bescheidenen Ansicht bedeutet, dass jeder Benutzercode, der zurückgegebene Zeichenfolgen mithilfe von auto speichert, beschädigt wird, wenn die Bibliotheken, die sie aufrufen, jemals umgestaltet werden, um std::string_view anstelle von std::string const& zurückzugeben.

Von nun an, zumindest für mich, muss "fast immer automatisch" werden, "fast immer automatisch, außer wenn es sich um Strings handelt".

36
Richard Hodges

Sie können den Konvertierungsoperator aus std :: string in std :: string_view verwenden:

std::string s = "hello world!";
std::string_view v = std::string_view(s).substr(6, 5);
2
CAF

So 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";

  return 0;
}
0
Alexander