Strings and string_view
7 pages · ~5 min✓ Reviewed
Builds on STL Containers and Algorithms. Next up: Templates and Modern C++.
std::string Mental Model and Core Operations
1. What a string is
std::string=std::basic_string<char>- Owns a contiguous, growable
charbuffer - Tracks size and capacity
c_str()anddata()are null-terminated
2. Cost of operations
| Operation | Cost | Note |
|---|---|---|
size [] front back | O(1) | [] out of range = UB |
at(i) | O(1) | throws out_of_range |
push_back append | amortised O(1) | capacity grows geometrically |
insert erase (middle) | O(n) | tail shifts |
find(x) | O(n*m) worst | returns npos |
substr(pos, len) | O(len) | copies; throws if pos > size() |
3. Pitfalls
- Not found gives npos, not -1 or 0
- Compare with
npos, never with anint reserve(n)pre-allocates, avoiding reallocation
cpp
s.reserve(1000); // one allocation auto p = s.find("ab"); if (p == std::string::npos) { // not found }
Remember
Use at() when unsure of the index. [] never checks, and find answers with npos.
Small String Optimisation and Memory Layout
1. What SSO Is
- SSO keeps short strings inside the string object, no heap
- Limit: ~15 chars libstdc++/MSVC, 22 libc++ (implementation-defined)
- Past the limit the string allocates on the heap
cpp
std::string s; std::cout << s.capacity();
empty capacity() reveals the inline limit
output
152. Moves and Invalidation
| Short (SSO) | Long (heap) | |
|---|---|---|
| Bytes live | inside object | on heap |
std::move | copies inline bytes | steals pointer, O(1) |
3. Rules
- Short strings are cache-friendly and allocation-free
- Small keys: take std::string by value
reserve()matters only past the inline buffer
C Strings vs std::string
1. C String Basics
- C string =
chararray ending in '\0' strlenis O(n): it scans for the terminatorstd::string::size()is O(1): length is stored
const char*==compares addresses, not contents- Content:
strcmp(a, b) == 0, orstd::string/string_view==
2. Crossing the Boundary
- const char*C string
- std::stringimplicit, scans for '\0'
- c_str() / data()explicit only
cpp
std::string s("a\0b", 3); // length given auto t = "a\0b"s; // also size 3 s.size(); // 3 std::strlen(s.c_str()); // 1
embedded '\0' is kept; C APIs stop at the first one
3. Comparison
| C string | std::string | |
|---|---|---|
| Memory | manual buffer sizing | manages itself, grows safely |
| Copy / join |
std::string_view and Dangling Pitfalls
1. View and Parameters
string_view(C++17): pointer + length, non-owning- Copy and
substrare O(1), no allocation - Takes
std::string,const char*, literals - Read-only params: use it, not
const std::string& - A literal to
const std::string&builds a temporary string
cpp
void show(std::string_view s); show("hello"); // no temporary string
2. How Views Dangle
| Cause | Why |
|---|---|
sv = std::string("hi") | temporary freed at ; |
| Return view of a local | local dies on return |
append, reserve, move | buffer reallocates |
cpp
std::string_view f() {
std::string s = "hi";
return s; // dangles
}3. Safety Rules
Conversions and String Streams
1. Number to String
std::to_string(n)takes int, long, double- double always uses %f:
3.14becomes3.140000 - Poor for floats: fixed 6 decimals
- Fast and locale-free:
std::to_chars(<charconv>)
2. String to Number
| No digits | Overflow | |
|---|---|---|
stoi stol stod | std::invalid_argument | std::out_of_range |
from_chars | no throw | no throw |
cpp
size_t pos = 0; int n = std::stoi("12abc", &pos); if (pos != 5) { /* junk left */ } int v; auto [p, ec] = std::from_chars(b, e, v); if (ec == std::errc()) { /* ok */ }
stoi gives 12 silently; check pos
from_chars: fast, non-throwing, locale-independent- Always check ec std::errc()==
3. String Streams
ostringstream: build with<<, read with.str()
std::format and Cheat Sheet
1. std::format
std::format("{} is {}", name, age)returns a std::string- C++20,
<format> - Format string checked at compile time
- Wrong argument count is a compile error
| Spec | Meaning |
|---|---|
{:>8} | right-align, width 8 |
{:<8} / {:^8} | left / centre |
{:08.3f} | zero-padded, 3 decimals |
{:x} / {:#b} | hex / binary with prefix |
{:+} | force sign |
2. Arguments and Output
{1} {0}reorder or reuse arguments- Literal braces:
{{and}} - Runtime format string needs std::vformat
std::format_to(std::back_inserter(s), ...)appends, no temporarystd::format_to_nlimits outputstd::print(C++23) writes straight to stdout
Check yourself
What does this print?
1: find returnsnpos-1converts tosize_t, which equalsnpos
std::string s = "hello"; std::cout << (s.find('z') == -1);
Spot the bug.
- The temporary string dies at the semicolon
svdangles, so printing it is undefined behaviour- Store a
std::stringand view that
std::string_view sv = std::string("hi") + "!"; std::cout << sv;
What does this print?
12 2.500000stoistops atasilently;to_stringuses 6 decimals
std::cout << std::stoi("12abc") << ' ' << std::to_string(2.5);