std::string and std::string_view
The char type holds exactly one character. 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
}+ joined the quoted text with name, size() returned the number of characters, and greeting[7] the character at position 7. The comparison name == "Ada" is true, and std::cout prints it as 1. Strings are compared character by character: the first differing pair decides, and if there is none, the shorter string is smaller. For "Ada" and "Bob", that pair is 'A' and 'B'.
A string owns its characters
A std::string stores its characters itself and allocates memory for them as needed. A copy of a string gets characters of its own, so changing the copy leaves the original alone. Characters are numbered from zero, and the last one sits at position size() - 1.
size() returns an unsigned number of type std::size_t. A loop counter over positions takes the same type. With int i, the comparison i < word.size() draws a compiler warning with the flags -Wall -Wextra, as in the course exercises.
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 its own. For such parameters, 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. Copying a view is cheap, 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. A const std::string& parameter would first have to create a temporary string for "Babbage". Characters are read as in a string, with size(), [] and a range-for loop, but 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.
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 right after 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.