Перейти к содержанию

Последнее обновление:2026-10-12

std::string_view в C++17

0.Проблема

string_view появился после C++17 и, по сути, является аналогом slice из leveldb; его цель — избежать копирования памяти и обеспечить эффективный substr.

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

1.Внутренняя реализация

string_view — это тип basic_string_view; видно, что _Traits использует char_traits по умолчанию, и это важно: ряд последующих функций выполняет ключевые операции с помощью некоторых функций-членов char_traits.

template<class _CharT, class _Traits = char_traits<_CharT> >
    class _LIBCPP_TEMPLATE_VIS basic_string_view;

typedef basic_string_view<char>     string_view;

Внутренние члены basic_string_view:

private:
    const   value_type* __data;
    size_type           __size;

Конструирование совместимо с string и const char*:

constexpr basic_string_view() noexcept;
constexpr basic_string_view(const basic_string_view&) noexcept = default;
basic_string_view& operator=(const basic_string_view&) noexcept = default;
template<class Allocator>
constexpr basic_string_view(const charT* str);
constexpr basic_string_view(const charT* str, size_type len);

Поддержка итераторов:

constexpr const_iterator begin() const noexcept;
constexpr const_iterator end() const noexcept;
constexpr const_iterator cbegin() const noexcept;
constexpr const_iterator cend() const noexcept;
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

Другие ключевые функции:

  • substr
  • remove_prefix
  • compare
  • find
  • ...

Начиная с C++20 поддерживаются starts_with, ends_with и contains; в slice из leveldb эти три функции поддерживались с самого начала.

Строковый литерал string_view для char*:

constexpr basic_string_view<char>     operator "" sv( const char *str,     size_t len ) noexcept;
constexpr basic_string_view<wchar_t>  operator "" sv( const wchar_t *str,  size_t len ) noexcept;
constexpr basic_string_view<char16_t> operator "" sv( const char16_t *str, size_t len ) noexcept;
constexpr basic_string_view<char32_t> operator "" sv( const char32_t *str, size_t len ) noexcept;

2.Ловушки при использовании

2.1 \0

string_view не обращает внимания на \0, для него важно фактическое число символов.

std::string_view s = "abc\0\0def"sv;
std::cout << "s: " << s.size() << " \"" << s << "\"\n";

Вывод: s: 8 "abcdef"

std::string_view str{"hello", 1};
std::cout << str.data() << std::endl; // 输出 hello,而不是h

Здесь ожидался вывод hello, но вывелось h.

2.2 Время жизни

string_view foo() {
    std::string s{"hello world"};
    return string_view{s};
}

В этом примере s выходит из области видимости, и string_view становится висячей ссылкой.

Время жизни

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

Похожие темы

Комментарии