A std::string_view is an inexpensive object that can look at the characters in an existing string.
It only records the beginning of the sequence of characters it sees and the length.
std::string_view can be constructed from a std::string.
Once set up, the view can be printed, indexed, or checked on its size in a similar fashion to a string.
But the view doesn't own any characters.
The characters still belong to the original std::string, and the view merely refers to them.
#include <iostream>
#include <string>
#include <string_view>
int main()
{
std::string text = "call stack";
// Refer to existing character data without owning it
std::string_view view = text;
std::cout << view << '\n';
return 0;
}
Another way a view can be created is from a string literal:
A string literal lasts for the life of the program, so a view of it remains valid.
The view can also give the total number of characters in the string as well as retrieve individual characters with brackets.
Such as a view of frame has a length of 5, and the 0 index element is f.
#include <iostream>
#include <string_view>
int main()
{
std::string_view view = "frame";
std::cout << "Length is " << view.size() << '\n';
std::cout << "First character is " << view[0] << '\n';
return 0;
}
Since a std::string_view doesn't own the characters it views, the characters must continue to exist as long as the view is in use.
For example, if the original string is deleted, the view holds a reference to invalid memory.
Using the view after that point is undefined behavior.
The same problem appears when the view's string refers to a temporary string that is destroyed as soon as the view is generated.
A function should not return a view to one of its local strings as the local string will be destroyed when the function exits.
The returned view would naturally then be referencing data which did not exist.
#include <iostream>
#include <string>
#include <string_view>
std::string_view make_view()
{
std::string local = "temporary";
return local;
}
int main()
{
// std::string_view bad = make_view();
return 0;
}
The safe route is to only ever create a view from character data that is known to be alive for long enough.
Some common examples of these are: a named std::string that you have defined that is still accessible, a string literal.
A std::string_view is often convenient to pass to functions which only need to view character data.
Since no copy of the string is made, passing the view is extremely cheap, even for very long strings.
This function can even check the size or individual characters without changing the source data or claiming ownership to it.
A function that takes a std::string_view can accept both a named std::string, as well as a string literal.
#include <iostream>
#include <string>
#include <string_view>
void show_length(std::string_view sv)
{
std::cout << "Length is " << sv.size() << '\n';
}
int main()
{
std::string name = "Stack Frame";
show_length(name);
show_length("literal text");
return 0;
}
Anyhow, it receives a sparing view of what is there and reads from this without copying the entire sequence.
Finally, std::string_view allows referencing existing character data efficiently, without ownership or copying:
The programmer has to make sure the underlying characters stay alive for as long as the view is used.
Once this condition is met, the view is essentially a read only window onto the text.
Exercise: std::string_viewStarter code, hints and solutionOpenClose
Practice: std::string_view
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Change name to Ada Lovelace and predict both length outputs. Explain where each string_view obtains its characters and why the storage is still alive.
Mission checklist
- Run the starter as a baseline, then predict the change requested in Your challenge.
- Make that change in your editor; use the lesson-specific hints if you need help.
- Compile and run your answer, then compare with the worked solution and explain the result.
Starter program
This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.
#include <iostream>
#include <string>
#include <string_view>
void show_length(std::string_view sv)
{
std::cout << "Length is " << sv.size() << '\n';
}
int main()
{
std::string name = "Stack Frame";
show_length(name);
show_length("literal text");
return 0;
}Hints
show_length receives a view of existing characters; it does not create an owning string copy. Count the space in "Stack Frame" when predicting size().
Change name before calling show_length(name), and keep name alive during the call. The literal argument also has valid backing storage; do not return a view into a destroyed local string.
Worked solution
name is now Ada Lovelace, containing twelve characters including the space. show_length observes them through string_view without owning a copy. name stays alive during the call; the literal example still has length twelve too.
#include <iostream>
#include <string>
#include <string_view>
void show_length(std::string_view sv)
{
std::cout << "Length is " << sv.size() << '\n';
}
int main()
{
std::string name = "Ada Lovelace";
show_length(name);
show_length("literal text");
return 0;
}
Example output
Length is 12
Length is 12
0 comments
No comments yet. Be the first.