TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #980 5.6K
​​Прелести рэнджей
#опытным

Рэнджи - это не просто сахар и "уродливые" палки pipe-синтаксиса, как думает некоторая часть плюсовиков. Это еще и в том числе про скорость и выразительность.

Возьмем пример из прошлого поста:

std::string text = "one two three four";
std::vector<std::string_view> strs;
boost::split(strs, text, boost::is_any_of(" "));


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

И на самом деле мы получаем кучу аллокаций.

Ну а что если нам нужна только третья подстрока? Каким бы красивым и проверенным не был бы вызов boost::split, он будет делать лишнюю работу + выделять память.

Можно конечно самим написать решение с циклом или подряд использовать std::string::find и это будет работать. Но там нужно аккуратно работать с индексами, желательно еще и отдельно тестировать этот код.

Но можно поступить проще и воспользоваться ренджами!

Рэнджи ленивые. Прям как студенты: всем на последнем курсе заранее дают задачу написать диплом, но обычно его начинают писать, когда научрук уже дает последнее китайское предупреждение вслед за пендалем, что нужно сделать работу уже вчера.

Но у рэнджей это скорее преимущество.

Пока у диапазона не спросишь следующий элемент - он его не вычислит. И в этом прелесть.

Мы просто пишем:

auto range = text | std::views::split(' ');


И абсолютно ничего не происходит! Но мы декларируем, что хотим получить поддиапазоны исходного текста, которые получены разбиением по разделителям.

С помощью ренджей мы даже можем оставить конкретный интересующий нас поддиапазон:

auto range = text | std::views::split(' ') | std::views::drop(2) | std::views::take(1);


Отбрасываем первые два элемента и берем только первый оставшийся. И опять же, ничего не происходит.

Вычисления происходят, когда мы пытаемся что-то узнать о результирующем диапазоне, например, пустой ли он:

if (range.empty()) {
std::cerr << "There are less than three words in text";
}


Если итоговый поддиапазон непустой, то в нем должен быть лишь один элемент, являющийся поддиапазоном оригинальной строки. То есть по сути легковесный view на нужную подстроку:

std::string_view str{*range.begin()};
std::cout << str << std::endl;
// OUTPUT: three


И здесь нет ни одной алллокации! Чисто работа с поддиапазонами. Это ровно то, чтобы мы бы делали руками через find, только в понятном декларативном стиле.

Возможно find работал бы и быстрее(а это еще проверить надо), но рэнджи предлагают более понятную альтернативу самописному коду.

Be expressive. Stay cool.

#cpp20
  • 👍 29
  • 🔥 15
  • ❤ 10
  • 😁 3
  • 🤯 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →