библиотека — типы общего назначенияlibrary — general-purpose types
Невладеющее, неизменяемое представление последовательности символов — указатель плюс длина, без null-terminator и без владения памятью. Основной сценарий — параметры функций без лишних аллокаций.A non-owning, immutable view of a character sequence — a pointer plus a length, no null terminator, no memory ownership. The primary use case is function parameters without unnecessary allocations.
std::string_view — это буквально пара «указатель на первый символ + длина», не владеющая данными, на которые указывает. Она не аллоцирует, не копирует, не хранит null-terminator — просто указывает на существующие символы, где бы они ни лежали: в std::string, в строковом литерале, в char[] буфере. Основное применение — параметры функций, принимающие и const char*, и std::string, и подстроку без единой лишней аллокации.std::string_view is literally a pair of "pointer to the first character + length," owning none of the data it points to. It doesn't allocate, doesn't copy, doesn't store a null terminator — it simply points at existing characters, wherever they live: inside a std::string, a string literal, a char[] buffer. Its primary use is function parameters that accept a const char*, a std::string, or a substring alike, without a single extra allocation.
void log(const std::string& msg);
log("hello");
// "hello" — const char*, неявно создаётся временный std::string,// "hello" is a const char*, an implicit temporary std::string is built,
// который аллоцирует память (если строка не влезает в SSO-буфер)// which allocates memory (unless the string fits the SSO buffer)
// только ради того, чтобы тут же быть уничтоженным// only to be destroyed right after
void log(std::string_view msg);
log("hello"); // указывает прямо на литерал, без аллокации// points straight at the literal, no allocation
std::string s = build();
log(s); // указывает на буфер s.data(), тоже без копирования// points at s.data()'s buffer, also without copying
log(std::string_view(s).substr(0, 3)); // substr на view — тоже без аллокации// substr on a view — also with no allocation
До C++17 не существовало способа принять «что угодно похожее на строку» без выбора между перегрузками и лишними аллокациями:Before C++17 there was no way to accept "anything string-like" without a choice between overloads and unnecessary allocations:
Функция с параметром const std::string&, вызванная с const char*, всё равно провоцирует неявное построение временного std::string — со всеми накладными расходами SSO-проверки и, при достаточно длинной строке, реальной аллокации в куче, хотя сама функция может лишь читать символы, ничего не изменяя и никуда не сохраняя.A function with a const std::string& parameter, called with a const char*, still triggers an implicit construction of a temporary std::string — with all the overhead of the SSO check and, for a sufficiently long string, an actual heap allocation, even though the function might only read the characters, changing and storing nothing.
Обходной путь — писать отдельные перегрузки под const char* и под const std::string& — удваивает объём кода на каждую такую функцию и всё равно не покрывает произвольную подстроку без выделения отдельного std::string под неё.The workaround — writing separate overloads for const char* and const std::string& — doubles the code for every such function and still doesn't cover an arbitrary substring without carving out a separate std::string for it.
std::string_view неявно конструируется и из const char*, и из std::string, и из подстроки — без копирования данных в обоих случаях. Одна сигнатура функции покрывает все три источника строки одновременно.std::string_view constructs implicitly from a const char*, from a std::string, and from a substring alike — without copying the data in any of these cases. One function signature covers all three string sources at once.
Как и optional/any, string_view пришёл из Library Fundamentals TS v1 (2015) — std::experimental::string_view в коде до C++17 ведёт себя практически идентично финальной версии.Like optional/any, string_view arrived from the Library Fundamentals TS v1 (2015) — std::experimental::string_view in pre-C++17 code behaves nearly identically to the final version.
Внутри — буквально два поля: указатель на данные и размер. Ни конструктор, ни деструктор ничего не аллоцируют и не освобождают — string_view не участвует в управлении временем жизни данных вообще, только читает их.Under the hood it's literally two fields: a data pointer and a size. Neither the constructor nor the destructor allocates or frees anything — string_view takes no part in managing the data's lifetime at all, it only reads it.
// концептуально — вся реализация:// conceptually — the entire implementation:
class string_view {
const char* data_;
size_t size_;
// никакого владения, никакого деструктора, который что-то освобождает// no ownership, no destructor that frees anything
};
std::string s = "hello world";
std::string_view sv = s; // указывает на s.data(), без копии// points at s.data(), no copy
std::string_view sub = sv.substr(0, 5); // "hello" — та же память, новый размер, всё ещё без копии// "hello" — same memory, new size, still no copy
s += "!"; // если это вызвало реаллокацию буфера s — sv и sub теперь dangling// if this reallocated s's buffer — sv and sub are now dangling
Последняя строка примера — ключевая иллюстрация того, почему string_view требует дисциплины: любая операция, инвалидирующая указатели/итераторы исходной строки (реаллокация при росте std::string, выход временного объекта из скоупа, уничтожение буфера), автоматически делает все существующие string_view на эти данные висячими — без единого предупреждения от компилятора.The last line of the example is the key illustration of why string_view demands discipline: any operation that invalidates the source string's pointers/iterators (a reallocation as a std::string grows, a temporary going out of scope, a buffer being destroyed) automatically leaves every existing string_view into that data dangling — without a single warning from the compiler.
Классическая ошибка: std::string_view sv = someFunc();, где someFunc() возвращает временный std::string по значению. Временный объект уничтожается в конце полного выражения (в момент завершения инициализации sv), а sv продолжает указывать на уже освобождённую память — use-after-free при первом же обращении к sv. string_view не продлевает время жизни временного объекта, в отличие от const T&.The classic bug: std::string_view sv = someFunc();, where someFunc() returns a temporary std::string by value. The temporary is destroyed at the end of the full expression (right after sv's initialization completes), and sv keeps pointing at already-freed memory — use-after-free on the very first access to sv. string_view does not extend a temporary's lifetime the way a const T& would.
string_view::data() возвращает указатель на первый символ, но не гарантирует наличие \0 сразу после последнего символа диапазона — в отличие от std::string::c_str(). Передать sv.data() напрямую в функцию, ожидающую null-terminated const char* (большинство C API), может прочитать за пределы видимого диапазона данных. Решение — либо явно собрать std::string через substr/конструктор из view, либо убедиться, что исходная строка гарантированно null-terminated и view покрывает её целиком.string_view::data() returns a pointer to the first character but does not guarantee a \0 right after the range's last character — unlike std::string::c_str(). Passing sv.data() directly to a function expecting a null-terminated const char* (most C APIs) can read past the visible data range. The fix is either to explicitly build a std::string via a constructor/substr from the view, or to make sure the source string is guaranteed null-terminated and the view covers it entirely.
В отличие от std::span<char> (C++20), string_view всегда read-only по дизайну — методы вроде substr, remove_prefix, remove_suffix лишь меняют, на какую часть исходных данных указывает сам view, не трогая символы. Если нужна изменяемая невладеющая последовательность символов, string_view для этого не подходит в принципе — нужен либо std::span<char>, либо прямая работа с указателем/итераторами std::string.Unlike std::span<char> (C++20), string_view is always read-only by design — methods like substr, remove_prefix, remove_suffix only change which portion of the source data the view itself points at, never touching the characters. If a mutable non-owning character sequence is needed, string_view simply isn't the right tool — you'd need either std::span<char> or direct work with a std::string's pointer/iterators.