99 votes

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

À l'aide de http://en.cppreference.com/w/cpp/string/basic_string_view comme référence, je ne vois aucun moyen de le faire de manière plus élégante:

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

Pire, l'approche naïve est un piège et les feuilles v un bancales référence à un temporaire:

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

Je semble me rappeler quelque chose comme il y a peut être un ajout à la bibliothèque standard de retourner une chaîne comme un point de vue:

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

Je ne peux penser à des 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'aucune de ces sont très gentils. Droit maintenant, la meilleure chose que je peux penser à est de l'utilisation d'alias pour simplement rendre les choses moins verbeux.

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

54voto

Richard Hodges Points 1972

Il y a le libre-fonction de l'itinéraire, mais à moins que vous fournissez également des surcharges pour std::string c'est un serpent à l'intérieur de la fosse.

#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 l'ensemble de la conception de string_view est un horror show qui va nous ramener à un monde de la segmentation et de la colère des clients.

mise à jour:

Même en ajoutant des surcharges pour std::string est un horror show. Voyez si vous pouvez repérer la subtile erreur de segmentation timebomb...

#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'un examen du code, ne serait pas non plus.

Je l'ai dit avant et je vais le dire encore une fois, au cas où quelqu'un sur le c++ comité observe, permettant les conversions implicites de std::string de std::string_view est une terrible erreur qui ne servira qu'à apporter de c++ dans le discrédit.

Mise à jour

Après avoir soulevé ce (pour moi) plutôt alarmant de la propriété de string_view sur le cpporg message du conseil, de mes préoccupations ont été remplis avec de l'indifférence.

Le consensus des conseils de ce groupe est qu' std::string_view doit jamais être retourné à partir d'une fonction, ce qui signifie que ma première offre ci-dessus est mauvais.

Il n'y a évidemment pas de compilateur d'aide pour attraper les fois où cela arrive par accident (par exemple par le modèle de l'expansion).

En conséquence, std::string_view doit être utilisé avec le plus grand soin, car à partir d'une gestion de la mémoire de point de vue, il est équivalent à un copiable pointeur pointant vers l'état d'un autre objet, qui n'existe plus. Toutefois, il ressemble et se comporte en tous points comme un type de la valeur.

Ainsi, le code comme ceci:

auto s = get_something().get_suffix();

Est sans danger lorsqu' get_suffix() renvoie un std::string (soit par valeur ou par référence)

mais est-UB si get_suffix() n'est jamais refait de retour d'un std::string_view.

Qui, à mon humble opinion signifie que tout le code de l'utilisateur qui stocke des chaînes renvoyées à l'aide de auto cassera si les bibliothèques, ils sont de l'appelant sont jamais refait de retour std::string_view à la place de std::string const&.

Donc à partir de maintenant, au moins pour moi, "presque toujours auto" devienne, "presque toujours automatique, sauf quand c'est des chaînes".

41voto

CAF Points 168

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

5voto

Alexander Points 150

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X