web-dev-qa-db-fra.com

Comment obtenir efficacement un `string_view` pour une sous-chaîne de` std :: string`

En utilisant http://fr.cppreference.com/w/cpp/string/basic_string_view comme référence, je ne vois aucun moyen de le faire plus élégamment:

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

Pire encore, l'approche naïve est un piège et laisse v une référence suspendue à un temporaire:

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

Je semble me rappeler quelque chose comme il pourrait y avoir un ajout à la bibliothèque standard pour renvoyer une sous-chaîne sous forme de vue:

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

Je peux penser aux solutions de contournement suivantes:

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);

Franchement, je ne pense pas qu'aucun d'entre eux sont très gentils. À l’heure actuelle, la meilleure chose à laquelle je puisse penser est d’utiliser des alias pour rendre les choses moins verbeuses.

using sv = std::string_view;
sv(s).substr(6, 5);
57
sehe

Il y a la route libre, mais à moins que vous ne fournissiez aussi des surcharges pour std::string, c'est une fosse aux serpents.

#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);
}

À mon humble avis, le design de string_view est un spectacle d'horreur qui nous ramènera dans un monde de segfaults et de clients en colère.

mettre à jour:

Même ajouter des surcharges pour std::string est un spectacle d'horreur. Voyez si vous pouvez repérer la subtile bombe à retardement segfault ...

#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);
}

Le compilateur n'a rien trouvé à signaler ici. Je suis certain qu'une révision du code ne le serait pas non plus.

Je l'ai déjà dit et je le répète, au cas où un membre du comité c ++ serait en train de regarder, autoriser les conversions implicites de std::string à std::string_view est une terrible erreur qui ne fera que discréditer c ++ .

Mettre à jour

Ayant soulevé cette propriété (qui me semble) plutôt alarmante de string_view sur le tableau d'affichage de cpporg, mes préoccupations ont été accueillies avec indifférence.

Le consensus des conseils de ce groupe est que std::string_view ne doit jamais être renvoyé d'une fonction, ce qui signifie que ma première offre ci-dessus est de mauvaise forme.

Bien sûr, il n’existe pas d’aide du compilateur pour saisir les heures où cela se produit par accident (par exemple, par le développement de modèles).

Par conséquent, std::string_view doit être utilisé avec le plus grand soin car, du point de vue de la gestion de la mémoire, il est équivalent à un pointeur copiable pointant vers l'état d'un autre objet, qui peut ne plus exister. Cependant, il ressemble et se comporte à tous les égards comme un type de valeur.

Donc code comme ceci:

auto s = get_something().get_suffix();

Est en sécurité lorsque get_suffix() renvoie un std::string (par valeur ou par référence)

mais est UB si get_suffix () est refactored pour retourner un std::string_view.

Ce qui, à mon humble avis, signifie que tout code utilisateur stockant les chaînes retournées à l'aide de auto sera rompu si les bibliothèques appelées sont refactorisées pour renvoyer std::string_view à la place de std::string const&.

Donc à partir de maintenant, au moins pour moi, "presque toujours auto" devra devenir "presque toujours auto, sauf quand ce sera une chaîne".

36
Richard Hodges

Vous pouvez utiliser l'opérateur de conversion de std :: string à std :: string_view :

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

Voici comment créer efficacement une sous-chaîne string_view.

#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