Ch9.13: string_view and cstring_view

Overview

::fast_io::string_view and ::fast_io::cstring_view are non-owning views over character sequences. They are lightweight (pointer + size) and avoid copying. The key difference is that cstring_view guarantees null-termination.

String views have many additional operations (search, trim, compare, etc.). You can skip the details for now and return to the Appendix §9.13.1 when you need them.

1. basic_string_view

A string_view is just a pointer and a size. Use it to pass strings to functions without overhead:


#include <fast_io_dsal/string_view.h>
#include <fast_io_dsal/string.h>
#include <fast_io.h>

void greet(::fast_io::string_view name) {
    ::fast_io::io::println("Hello, ", name, "!");
}

int main() {
    ::fast_io::string str{"Alice"};
    greet(str);           // From string (implicit conversion)
    greet("Bob");         // From string literal

    // Sub-view operations
    ::fast_io::string_view sv{"Hello, World!"};
    auto prefix = sv.subview_front(5zu);  // "Hello"
    auto suffix = sv.subview_back(6zu);   // "World!"
    auto middle = sv.subview(7zu, 5zu);   // "World"

    // Trim operations
    ::fast_io::string_view padded{"  hello  "};
    auto trimmed = padded.trim_subview_c_space(); // "hello"

    // Search
    auto pos = sv.find_character('W'); // 7
    bool has = sv.contains_character('o'); // true
}

Character type variants

Alias Character Type
::fast_io::string_viewchar
::fast_io::wstring_viewwchar_t
::fast_io::u8string_viewchar8_t
::fast_io::u16string_viewchar16_t
::fast_io::u32string_viewchar32_t

2. cstring_view

::fast_io::cstring_view is a string_view with a null-termination guarantee. It can be constructed from string (which is always null-terminated) and from string literals. Use it when interfacing with C APIs:


#include <fast_io_dsal/string.h>
#include <fast_io_dsal/cstring_view.h>
#include <fast_io.h>

void c_api_wrapper(::fast_io::cstring_view csv) {
    // Safe to pass .c_str() to C functions
    // ::some_c_function(csv.c_str());
}

int main() {
    ::fast_io::string str{"Hello"};
    ::fast_io::cstring_view csv{str}; // OK: string is always null-terminated
    c_api_wrapper(csv);
}

3. Dangling string_view

string_view does not own its data. It is a pointer and a size — if the underlying buffer moves or is freed, the view becomes dangling.

What is safe: no dangling from temporaries

fast_io::string_view and fast_io::span only accept lvalue references. This means you cannot accidentally create a view from a temporary — the compiler rejects it:


// This does NOT compile — string_view only binds to lvalues
::fast_io::string_view get_name() {
    ::fast_io::string temp{"hello"};
    return temp; // ERROR: cannot create string_view from a local that is about to die
}

So the classic dangling pattern from other languages is not possible here. The compiler protects you from views over destroyed objects.

What is dangerous: reallocation invalidates views

Danger: A string_view over a string becomes dangling when the string reallocates. Operations like push_back(), insert_index(), replace_index(), append(), and operator+= may trigger a reallocation, moving the buffer to new memory. Any existing string_view still points to the old (freed) buffer.

::fast_io::string s{"Hello, World!"};
::fast_io::string_view sv{s}; // sv points into s's buffer

// DANGER: this may reallocate s's internal buffer
s.append(" this is a long string that forces reallocation");

// sv is now dangling — it points to freed memory
// Reading sv is undefined behaviour

The same applies to span over vector or deque: any operation that grows the container may invalidate existing views.

Rule of thumb: do not hold a string_view (or span) across any operation that might mutate the underlying container.

To detect dangling views during testing, you can use Wasm MemTag (WebAssembly memory tagging). When compiled for Wasm with memory tagging enabled, accesses to freed memory are caught at runtime, making dangling-view bugs detectable.

Key takeaways