Если параметр представляет тип std::string, то мы можем передавать такому параметру как объект std::string, так и строковый литерал. Например:
#include <iostream>
#include <string>
void print(const std::string&);
int main()
{
std::string message{"hello"};
print(message); // можем передать std::string
print("Hello Work"); // можем передать строковый литерал
}
void print(const std::string& text)
{
std::cout << text << std::endl;
}
Здесь строка передается по ссылке, что позволяет избежать ненужного копирования символов. А модификатор const защищает строку от изменения. Однако несмотря на то, что строка
передается по ссылке, когда параметру передаем строковый литерал, то в памяти в процессе преобразования строкового литерала к типу std::string
все равно будет идти копирование символов и соответственно дополнительные выделения памяти, что отрицательно влияет на производительность.
Тип std::string_view призван решить данную проблему. Он определен в модуле <string_view> и действует аналогично const std::string с одним исключением -
string_view не копирует символы строкового объекта вне зависимости, что он представляет - тип std::string, строковый литерал или символьный масссив.
Поэтому в качестве типа параметра оптимальнее использовать std::string_view, а не константную ссылку const std::string&.
При этом не важно, что параметр может передаваться по значению, а не по ссылке - копирование символов все равно не будет происходить. В своей внутренней реализации std::string_view
лишь копирует длину строки и указатель на последовательность символов.
Однако стоит отметить, что работа с типом string_views подразумевает, что символы строки не будут изменяться, поскольку тип
string_views в своей внутренней реализации представляет константу вне зависимости от того, применяется ли к параметру модификатор const.
Изменим выше определенную программу, применив тип std::string_view:
#include <iostream>
#include <string>
#include <string_view>
void print(std::string_view);
int main()
{
std::string message{"hello"};
print(message); // можем передать std::string
print("Hello Work"); // можем передать строковый литерал
}
void print(std::string_view text)
{
std::cout << text << std::endl;
}
В остальном, тип std::string_view реализует большинство тех же функций, что и тип std::string. Например, найдем в строке, которая представляет string_view,
количество слов:
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
std::vector<std::string_view> get_words(std::string_view);
int main()
{
std::string text = " An apple a day keeps the doctor away."; // Исходный текст
std::vector<std::string_view> words = get_words(text);
// выводим количество слов
std::cout << "\nText contains " << words.size() << " words:" << std::endl;
// выводим все слова на консоль
for (const auto& word : words)
{
std::cout << word << std::endl;
}
}
std::vector<std::string_view> get_words(std::string_view text)
{
const std::string_view separators{ " ,;:.\"!?'*\n" };
std::vector<std::string_view> words; // вектор для хранения слов
size_t start { text.find_first_not_of(separators) }; // начальный индекс первого слова
while (start != std::string_view::npos) // проходим, пока в строке не окажется других символов, кроме separators
{
size_t end = text.find_first_of(separators, start + 1); // находим, где кончается слово
if (end == std::string_view::npos) // если НЕ найден ни один из символов-разделителей
end = text.length(); // устанавливаем переменную end на конец текста
words.push_back(text.substr(start, end - start)); // добавляем в вектор слово
start = text.find_first_not_of(separators, end + 1); // находим начальный индекс следующего слова и переустанавливаем start
}
return words;
}
По сути здесь реализована та же программа по подсчету слов, что и в прошлой статье, только в качестве текста передается строка типа std::string_view. И для выделения слов
вызываем ряд функций типа, которые эквиваленты соответствующим функциям типа std::string: find_first_not_of(), find_first_of(), length().
Стоит отметить, что для работы со строками Unicode также имеются свои типы: std::wstring_view, std::u8string_view,
std::u16string_view и std::u32string_view. Работа с этими типами будет аналогична работе с std::string_view.