C++ Standard Library · Lesson 3

std::string & std::string_view

A real, owning, growable text type — plus the lightweight non-owning "window" you pass around to avoid copying it. When to use which, and the dangling trap to dodge.

🎯 Handle text the modern way — no char*, no leaks
The one idea

std::string owns its characters (think "vector<char> with text powers"). std::string_view (C++17) is a non-owning window into characters someone else owns — cheap to pass, but it must never outlive the buffer it points at.

01 std::string — owning text done right

Forget char*, manual malloc, and strcpy. std::string owns a growable buffer of characters, manages the memory for you (RAII), and gives you concatenation, search, and slicing as methods.

#include <string>

std::string s = "hello";
s += ", world";            // concatenate in place → "hello, world"
s.size();                  // 12   (length() is a synonym)
s[0];                      // 'h'  — like a vector of char
s.substr(7);               // "world"   — slice from index 7
s.substr(0, 5);            // "hello"   — slice [0, 5)
s.find("world");          // 7    (or std::string::npos if absent)

std::string greet = "hi " + name;   // build by +
std::cout << s.c_str();    // borrow a const char* for an old C API
Run on godbolt.org (-std=c++17+).

It's a container too

string is basically a sequence of char: size(), [], at(), begin()/end(), range-for, push_back — all the vector vocabulary works, plus text methods.

npos means "not found"

find returns the index, or the sentinel std::string::npos if the needle isn't there. Always test if (pos != std::string::npos) before using it.

Convert to/from numbers

std::stoi("42") → int; std::stod → double; std::to_string(42) → "42". (For formatted output, std::format — §05.)

Source: cppreference — std::basic_string (std::string is basic_string<char>).

02 The operations you'll actually use

You want to…Call
lengths.size() / s.length() / s.empty()
appends += t; · s.append(t) · s.push_back('x')
slices.substr(pos, len)
searchs.find(t), rfind, find_first_of (returns index or npos)
test prefix/suffix C++20s.starts_with(t), s.ends_with(t)
replace / insert / erases.replace(pos,len,t), s.insert, s.erase
comparea == b, a < b (lexicographic — operators just work)
hand to a C APIs.c_str() → null-terminated const char*
💡 Comparison operators just work Unlike C strings (where == compares pointers and you need strcmp), std::string overloads ==, <, etc. to compare contents. This is also why string drops straight into a map or set key (Lessons 4–5).

03 std::string_view — borrow, don't copy C++17

Every time you pass a std::string by value, you copy the whole buffer. Often a function only wants to read the characters. std::string_view is a tiny object — just a pointer + length — that looks at characters owned by someone else. Copying a string_view copies two machine words, never the text.

std::string (OWNS the bytes) H e l l o , W o r l d string_view{ ptr, len=6 } no bytes of its own — just looks here If the string dies, the buffer is freed — the view now points at garbage (dangling).
A string_view is a cheap "I'm only reading" handle. It owns nothing, so its lifetime must be inside the owner's.
#include <string_view>

// One signature accepts std::string, char* literal, or a slice — with NO copy:
size_t count_vowels(std::string_view text) {
    size_t n = 0;
    for (char c : text)
        if (std::string_view("aeiou").find(c) != std::string_view::npos) ++n;
    return n;
}

count_vowels("hello");            // from a literal — no allocation
std::string s = "world";
count_vowels(s);                  // from a std::string — no copy
💡 The rule of thumb for parameters For a read-only string parameter, take std::string_view by value. It binds to a std::string, a string literal, or a substring without ever copying — one signature, zero allocations.

Source: cppreference — std::string_view.

04 The dangling trap — and when to use which

A string_view owns nothing, so it's only valid while the characters it points at are alive. Two bugs to memorize:

// BUG 1: returning a view of a local string
std::string_view bad() {
    std::string tmp = "oops";
    return tmp;     // tmp is destroyed on return → view dangles
}

// BUG 2: a view of a temporary that's already gone
std::string_view v = std::string("temp") + "x";   // temporary dies at the ';'
std::cout << v;   // undefined behavior
⚠ Don't store or return a view of something short-lived string_view is for passing through and reading, not for owning or stashing. If you need to keep the text, store a std::string (it copies and owns).
SituationUse
A read-only text parameterstd::string_view (by value)
A class member / something you keepstd::string (owns it)
Returning newly built textstd::string (by value)
A function that modifies the textstd::string& (mutable reference)

Source: Core Guidelines on string_view for non-owning read-only parameters.

05 Bonus: building strings cleanly with std::format C++20

Concatenating with + and to_string gets ugly fast. std::format brings Python-style {} formatting to C++:

#include <format>

std::string msg = std::format("{} has {} points ({:.1f}%)", name, pts, pct);
// "Ada has 42 points (87.5%)"  — types deduced, no + soup, no stream manip
🎯 Why it matters std::format (and std::print in C++23) is the modern way to build and emit text — type-safe, readable, fast. We'll see it again in the I/O lesson. If your compiler lacks it, the {fmt} library is the identical original.

Source: cppreference — std::format.

06 Check yourself

What does std::string_view actually hold?
For a function parameter that only reads some text, the idiomatic type is:
s.find("x") returns std::string::npos. That means:
Why is returning a string_view of a local std::string a bug?

07 Flashcards

Q: std::string vs std::string_view in one line each?
A: string owns a growable char buffer (manages memory). string_view is a non-owning pointer+length window into chars someone else owns.
Q: When should a parameter be string_view?
A: When it's read-only. One signature then accepts a std::string, a string literal, or a substring with zero copies.
Q: What's the lifetime rule for string_view?
A: The view must not outlive the buffer it points at. Don't return or store a view of a local/temporary string — that dangles.
Q: How do C++ string comparisons differ from C?
A: std::string overloads ==, <, etc. to compare contents. C strings (char*) compare pointers — you need strcmp.
Q: Numbers to/from strings?
A: std::stoi/stod parse a string to a number; std::to_string goes the other way; std::format builds rich text with {} placeholders.
Q: How do you pass a std::string to an old C API?
A: s.c_str() gives a null-terminated const char* viewing the string's buffer (valid until the string is modified/destroyed).
👩‍🏫 I'm your teacher — ask me anything

Try: "is this string_view safe?" and paste a snippet. Or "show me a tokenizer using find + substr". We'll wire text handling to the containers from here.