Подтвердить что ты не робот

Как эффективно получить `string_view` для подстроки` std::string `

Используя http://en.cppreference.com/w/cpp/string/basic_string_view в качестве ссылки, я не вижу возможности сделать это более элегантно:

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

Хуже того, наивный подход - это ловушка и оставляет v болтливую ссылку на временную:

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

Кажется, я помню что-то вроде добавления в стандартную библиотеку для возврата подстроки в виде представления:

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

Я могу вспомнить следующие обходные пути:

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

Честно говоря, я не думаю, что все это очень приятно. Прямо сейчас самое лучшее, что я могу придумать, это использовать псевдонимы, чтобы просто сделать вещи менее подробными.

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

Ответ 1

Там есть маршрут свободной функции, но если вы также не обеспечиваете перегрузки для std::string, это змеиная яма.

#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 весь дизайн string_view - это шоу ужасов, которое вернет нас в мир segfaults и сердитых клиентов.

обновление:

Даже добавление перегрузок для std::string - это шоу ужасов. Посмотрите, можете ли вы заметить тонкую временную память 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);
}

Компилятор ничего не предупредил. Я уверен, что обзор кода тоже не будет.

Я уже говорил об этом раньше, и я скажу это снова, на случай, если кто-либо из комитета С++ будет смотреть, , позволяющий неявные преобразования от std::string до std::string_view - ужасная ошибка, которая будет только служить приведите С++ в дурную славу.

Update

Подняв это (для меня) довольно тревожное свойство string_view на доске объявлений cpporg, мои проблемы были удовлетворены безразличием.

Консенсус рекомендаций этой группы состоит в том, что std::string_view никогда не должен возвращаться из функции, а это значит, что мое первое предложение выше - плохая форма.

Конечно, никакая компилятор не помогает ловить время, когда это происходит случайно (например, через расширение шаблона).

В результате std::string_view следует использовать с максимальной осторожностью, потому что с точки зрения управления памятью это эквивалентно скопируемому указателю, указывающему на состояние другого объекта, который больше не может существовать. Однако он выглядит и ведет себя во всех других отношениях, таких как тип значения.

Таким образом, код выглядит следующим образом:

auto s = get_something().get_suffix();

Безопасен, когда get_suffix() возвращает std::string (по значению или ссылке)

но UB, если get_suffix() когда-либо реорганизован для возврата std::string_view.

Что в моем скромном представлении означает, что любой код пользователя, в котором хранятся возвращенные строки с использованием auto, будет разбит, если библиотеки, которые они вызывают, когда-либо реорганизованы, чтобы вернуть std::string_view вместо std::string const&.

Итак, отныне, по крайней мере для меня, "почти всегда авто" должен стать "почти всегда авто, кроме случаев, когда он строит".

Ответ 2

Вы можете использовать оператор преобразования от std::string до std:: string_view:

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

Ответ 3

Вот как вы можете эффективно создать подстроку 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;
}