std::string and std::string_view
What you'll learn:
- store and compare text in a
std::string; - pass text to a function through a
std::string_viewwithout a copy; - spot a view that has outlived its string;
- tell a C array from a
std::arrayand find an array's length.

Picture a rack of letter tiles, like the one in a word board game. The tiles on the rack are its own: you can add a new one or take one away, and how many there are is decided as the game goes. That is how a string works in C++.
Now take a cardboard frame with a window cut in it and lay it over someone else's rack. Several tiles in a row show through the window, but the frame has no tiles of its own. It remembers only two numbers: which tile the window starts at and how many tiles it shows. That is how a string view works, and it is the second half of this lesson.
The char type holds exactly one character, like a single tile. A name, a word or a phrase consists of many characters, and how many is not known in advance. Such text is stored in a string: a variable of type std::string from the <string> header.
#include <iostream>
#include <string>
int main() {
std::string name = "Ada";
std::string greeting = "Hello, " + name;
std::cout << greeting << ' ' << greeting.size() << '\n'; // Hello, Ada 10
std::cout << greeting[0] << greeting[7] << '\n'; // HA
std::cout << (name == "Ada") << (name < "Bob") << '\n'; // 11
}Let's go through the three lines of output:
+joins the quoted text with the stringname, andsize()returns the number of characters:10.greeting[0]andgreeting[7]give the characters at positions0and7:HandA.- The comparison
name == "Ada"is true, andstd::coutprints it as1. The comparisonname < "Bob"is true too.
greeting.size() calls a function that belongs to the string itself: the variable name, a dot, the function name and parentheses.
Strings are compared character by character: the first differing pair decides. If there is no such pair, the shorter string is smaller. For "Ada" and "Bob", the first pair is 'A' and 'B'.
A string owns its characters
A std::string stores its characters itself and allocates memory for them as needed, like a rack that tiles are added to. A copy of a string gets characters of its own, so if you change the copy, the original stays the same. Characters are numbered from zero, and the last one sits at position size() - 1.
size() returns an unsigned number of type std::size_t, declared in the <cstddef> header. A loop counter over positions takes the same type. If you declare the counter as int i, the compiler with the flags -Wall -Wextra, as in the course exercises, warns about the comparison i < word.size().
std::string word = "code";
for (std::size_t i = 0; i < word.size(); ++i) {
std::cout << i << word[i] << ' '; // 0c 1o 2d 3e
}If positions are not needed, a range-for loop does the job: for (char c : word) puts each character into c in turn.
A string view
A function that only reads text needs no copy of the string of its own. For the parameter of such a function, there is the std::string_view type from the <string_view> header. It is a view: it stores the address of the first character and the length, but not the characters themselves. It is that frame with a window: it lies over someone else's characters and remembers where the window starts and how many characters it shows.
Copying a view is cheap, since it is only two numbers. So a std::string_view parameter is passed by value.
#include <iostream>
#include <string>
#include <string_view>
void print_length(std::string_view text) {
std::cout << text << ' ' << text.size() << '\n';
}
int main() {
std::string name = "Ada";
print_length(name); // Ada 3
print_length("Babbage"); // Babbage 7
}A std::string_view parameter accepts both a std::string and text in double quotes, and copies nothing. If the parameter were a const std::string&, a call with "Babbage" would first make the program create a temporary string. A view's characters are read as in a string, with size(), [] and a range-for loop. They cannot be changed through a view.
A view may be used only while the string it looks at is alive. Unlike a const reference, a view does not extend the life of a temporary string. This is where the analogy stops working. When the rack is taken away, a real frame shows an empty table, but a view keeps reading memory where the characters no longer are.
Step through the script: watch how the view's address and length change while the string's characters stay put, and what full is left with once the temporary string is destroyed.
1std::string first = "Ada";2std::string_view v = first;3v.remove_prefix(1);4std::string_view full = first + " Lovelace";5std::cout << full << '\n';
first owns its characters: 3 characters sit in its own memory. Press Next.
Common mistake
A view is created from a temporary string:
std::string first = "Ada";
std::string_view full = first + " Lovelace"; // ✗
std::cout << full << '\n';warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl]Clang warns, but the program builds, and not every compiler catches this mistake. first + " Lovelace" creates a temporary string, which is destroyed as soon as full is declared. The view keeps looking at its characters, so it becomes dangling, and reading full is undefined behavior.
The same happens to a view of a string that a function returns by value: such a string is temporary too. To keep the result, declare full as a std::string.
Key points
- A
std::stringowns its characters, and a copy of it gets characters of its own. - A
std::string_viewstores only the address of the first character and the length, so it is passed by value. - A view must not be read after its string is destroyed: that is undefined behavior.
- A character's position and
size()have the unsigned typestd::size_t.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.