Skip to content

Last updated:2026-10-12

C++17 std::string_view

0.The problem

string_view was introduced after C++17; it is essentially the slice in leveldb, and its purpose is to solve memory copying and provide an efficient substr.

However, it also introduces problems with pointers and references. Since a string_view does not own the content it points to, compared with Rust it is merely a borrow: if the object that owns the content is released early, a dangling reference problem arises. Rust analyzes variable lifetimes at compile time to guarantee that borrowed resources are not released while still in use. C++, however, performs no such checking, so it must be guaranteed manually.

1.Internal implementation

string_view is a basic_string_view type. As you can see, _Traits uses the default char_traits, which is important: several of the functions below rely on member functions of char_traits to perform their core operations.

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

typedef basic_string_view<char>     string_view;

Members of basic_string_view:

private:
    const   value_type* __data;
    size_type           __size;

Construction is compatible with string and 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);

Iterator support:

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;

Other core functions:

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

Since C++20 it also supports starts_with, ends_with, and contains; these three were supported in leveldb's slice from the very beginning.

A string_view literal for 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.Pitfalls in use

2.1 \0

string_view does not care about \0; it cares about the actual number of characters.

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

Output: s: 8 "abcdef"

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

Here hello is expected to be printed, but h is printed instead.

2.2 Lifetime

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

In this example, once s goes out of scope, the string_view becomes a dangling reference.

Lifetime

std::string_view does not own the underlying character storage; make sure the lifetime of the referenced object covers the entire period of use.

Comments