Skip to content

← Containers, Strings, Algorithms step 2 of 5

Medium Primitives

Reading text you do not own

std::string owns its characters. Every time you build one you may allocate, and every substr you take from one definitely does — it returns a brand new std::string holding a copy of the characters you asked for.

For a function that only reads text, all of that is waste, and it is the waste that parsing code is made of. Splitting a line into eight fields allocates eight strings, compares them, and frees them.

std::string_view    // a pointer and a length. That is the entire type.

It refers to characters somebody else owns. Copying one copies two machine words. substr on a view returns another view — same characters, different bounds, no allocation. It has find, starts_with, ==, iterators: nearly the read-only half of std::string‘s interface, and none of the ownership.

As a parameter

void handle(const std::string& s);   // a caller with a literal must build one
void handle(std::string_view s);     // takes a literal, a string, or a slice

std::string_view is the right parameter type for “text I will read and not keep”. Pass it by value — it is two words, and a reference to it costs more than it saves. This is one of the few types where by-value is not only acceptable but correct.

The two things that will bite you

1. It does not own, so it can dangle.

std::string_view bad() {
    std::string local = build();
    return local;          // the characters die at the closing brace
}

std::string_view worse = std::string("temporary");   // dead immediately

A view is only valid while its owner is alive and unmoved. Take one as a parameter, use it, let it go. Do not store one in a struct that outlives the call, and do not return one that points at a local. The same rule as Track 4’s raw pointers, applied to characters.

2. It is not null-terminated.

A view can name the middle of a larger buffer, so data() is not a C string and must never be handed to printf, fopen, strlen, or anything else that reads until it finds a zero. When a C API needs a const char*, build a std::string — deliberately, at that one point.

Your task

int count_fields(std::string_view record, std::string_view wanted);

record is a comma-separated line. Return how many of its fields are exactly equal to wanted. A record with no comma has one field; an empty record has one field, which is empty.

The signature is already right. The body is what someone writes on their first day with string_view: it copies everything into std::strings and works with those.

The harness counts heap allocations while your function runs, and prints the total. It must be zero.