In the previous lesson, we talked about C-style strings, and the dangers of using them. C-style strings are fast, but they’re not as easy to use and as safe as std::string
.
But std::string
(which we covered in lesson 4.12 -- An introduction to std::string), has some of its own downsides, particularly when it comes to const strings.
Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> #include <string> int main() { char text[]{ "hello" }; std::string str{ text }; std::string more{ str }; std::cout << text << ' ' << str << ' ' << more << '\n'; return 0; } |
As expected, this prints
hello hello hello
Internally, main
copies the string “hello” 3 times, resulting in 4 copies. First, there is the string literal “hello”, which is known at compile-time and stored in the binary. One copy is created when we create the char[]
. The following two std::string
objects create one copy of the string each. Because std::string
is designed to be modifiable, each std::string
must contain its own copy of the string, so that a given std::string
can be modified without affecting any other std::string
object.
This holds true for const std::string
, even though they can’t be modified.
Introducing std::string_view
Consider a window in your house, looking at a car sitting on the street. You can look through the window and see the car, but you can’t touch or move the car. Your window just provides a view to the car, which is a completely separate object.
C++17 introduces another way of using strings, std::string_view
, which lives in the <string_view> header.
Unlike std::string
, which keeps its own copy of the string, std::string_view
provides a view of a string that is defined elsewhere.
We can re-write the above code to use std::string_view
by replacing every std::string
with std::string_view
.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> #include <string_view> int main() { std::string_view text{ "hello" }; // view the text "hello", which is stored in the binary std::string_view str{ text }; // view of the same "hello" std::string_view more{ str }; // view of the same "hello" std::cout << text << ' ' << str << ' ' << more << '\n'; return 0; } |
The output is the same, but no more copies of the string “hello” are created. The string “hello” is stored in the binary and is not allocated at run-time. text
is only a view onto the string “hello”, so no copy has to be created. When we copy a std::string_view
, the new std::string_view
observes the same string as the copied-from std::string_view
is observing. This means that neither str
nor more
create any copies. They are views onto the existing string “hello”.
std::string_view
is not only fast, but has many of the functions that we know from std::string
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> #include <string_view> int main() { std::string_view str{ "Trains are fast!" }; std::cout << str.length() << '\n'; // 16 std::cout << str.substr(0, str.find(' ')) << '\n'; // Trains std::cout << (str == "Trains are fast!") << '\n'; // 1 // Since C++20 std::cout << str.starts_with("Boats") << '\n'; // 0 std::cout << str.ends_with("fast!") << '\n'; // 1 std::cout << str << '\n'; // Trains are fast! return 0; } |
Because std::string_view
doesn’t create a copy of the string, if we change the viewed string, the changes are reflected in the std::string_view
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <string_view> int main() { char arr[]{ "Gold" }; std::string_view str{ arr }; std::cout << str << '\n'; // Gold // Change 'd' to 'f' in arr arr[3] = 'f'; std::cout << str << '\n'; // Golf return 0; } |
We modified arr
, but str
appears to be changing as well. That’s because arr
and str
share their string. When you use a std::string_view
, it’s best to avoid modifications to the underlying string for the remainder of the std::string_view
‘s life to prevent confusion and errors.
Best practice
Usestd::string_view
instead of C-style strings.
Prefer std::string_view
over std::string
for read-only strings, unless you already have a std::string
.
View modification functions
Back to our window analogy, consider a window with curtains. We can close either the left or right curtain to reduce what we can see. We don’t change what’s outside, we just reduce the visible area.
Similarly, std::string_view
contains functions that let us manipulate the view of the string. This allows us to change the view without modifying the viewed string.
The functions for this are remove_prefix
, which removes characters from the left side of the view, and remove_suffix
, which removes characters from the right side of the view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> #include <string_view> int main() { std::string_view str{ "Peach" }; std::cout << str << '\n'; // Ignore the first character. str.remove_prefix(1); std::cout << str << '\n'; // Ignore the last 2 characters. str.remove_suffix(2); std::cout << str << '\n'; return 0; } |
This program produces the following output:
Peach each ea
Unlike real curtains, a std::string_view
cannot be opened back up. Once you change the visible area, you can’t go back (There are tricks which we won’t go into).
std::string_view works with non-null-terminated strings
Unlike C-style strings and std::string
, std::string_view
doesn’t use null terminators to mark the end of the string. Rather, it knows where the string ends because it keeps track of its length.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <iterator> // For std::size #include <string_view> int main() { // No null-terminator. char vowels[]{ 'a', 'e', 'i', 'o', 'u' }; // vowels isn't null-terminated. We need to pass the length manually. // Because vowels is an array, we can use std::size to get its length. std::string_view str{ vowels, std::size(vowels) }; std::cout << str << '\n'; // This is safe. std::cout knows how to print std::string_views. return 0; } |
This program prints:
aeiou
Ownership issues
Being only a view, a std::string_view
‘s lifetime is independent of that of the string it is viewing. If the viewed string goes out of scope, std::string_view
has nothing to observe and accessing it causes undefined behavior. The string that a std::string_view
is viewing has to have been created somewhere else. It might be a string literal that lives as long as the program does or it was created by a std::string
, in which case the string lives until the std::string
decides to destroy it or the std::string
dies. std::string_view
can’t create any strings on its own, because it’s just a view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <iostream> #include <string> #include <string_view> std::string_view askForName() { std::cout << "What's your name?\n"; // Use a std::string, because std::cin needs to modify it. std::string str{}; std::cin >> str; // We're switching to std::string_view for demonstrative purposes only. // If you already have a std::string, there's no reason to switch to // a std::string_view. std::string_view view{ str }; std::cout << "Hello " << view << '\n'; return view; } // str dies, and so does the string that str created. int main() { std::string_view view{ askForName() }; // view is observing a string that already died. std::cout << "Your name is " << view << '\n'; // Undefined behavior return 0; } |
What's your name? nascardriver Hello nascardriver Your name is �P@�P@
When we created str
and filled it with std::cin
, it created its internal string in dynamic memory. When str
goes out of scope at the end of askForName
, the internal string dies along with str
. The std::string_view
doesn’t know that the string no longer exists and allows us to access it. Accessing the released string through view
in main
causes undefined behavior, which on the author’s machine produced weird characters.
The same can happen when we create a std::string_view
from a std::string
and modify the std::string
. Modifying a std::string
can cause its internal string to die and be replaced with a new one in a different place. The std::string_view
will still look at where the old string was, but it’s not there anymore.
Warning
Make sure that the underlying string viewed with a std::string_view
does not go out of scope and isn’t modified while using the std::string_view.
Converting a std::string_view
to a std::string
An std::string_view will not implicitly convert to a std::string
, but can be explicitly converted:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <iostream> #include <string> #include <string_view> void print(std::string s) { std::cout << s << '\n'; } int main() { std::string_view sv{ "balloon" }; sv.remove_suffix(3); // print(sv); // compile error: won't implicitly convert std::string str{ sv }; // okay print(str); // okay print(static_cast<std::string>(sv)); // okay return 0; } |
This prints:
ball ball
Converting a std::string_view
to a C-style string
Some old functions (such as the old strlen function) still expect C-style strings. To convert a std::string_view
to a C-style string, we can do so by first converting to a std::string
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <cstring> #include <iostream> #include <string> #include <string_view> int main() { std::string_view sv{ "balloon" }; sv.remove_suffix(3); // Create a std::string from the std::string_view std::string str{ sv }; // Get the null-terminated C-style string. const char* szNullTerminated{ str.c_str() }; // Pass the null-terminated string to the function that we want to use. std::cout << str << " has " << std::strlen(szNullTerminated) << " letter(s)\n"; return 0; } |
This prints:
ball has 4 letter(s)
However, creating a std::string
every time we want to pass a std::string_view
as a C-style string is expensive, so this should be avoided if possible.
Opening the window (kinda) via the data() function
The string being viewed by a std::string_view
can be accessed by using the data()
function, which returns a C-style string. This provides fast access to the string being viewed (as a C-string). But it should also only be used if the std::string_view
‘s view hasn’t been modified (e.g. by remove_prefix
or remove_suffix
) and the string being viewed is null-terminated.
In the following example, std::strlen
doesn’t know what a std::string_view
is, so we need to pass it str.data()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <cstring> // For std::strlen #include <iostream> #include <string_view> int main() { std::string_view str{ "balloon" }; std::cout << str << '\n'; // We use std::strlen because it's simple, this could be any other function // that needs a null-terminated string. // It's okay to use data() because we haven't modified the view, and the // string is null-terminated. std::cout << std::strlen(str.data()) << '\n'; return 0; } |
balloon 7
When a std::string_view
has been modified, data()
doesn’t always do what we’d like it to. The following example demonstrates what happens when we access data()
after modifying the view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <cstring> #include <iostream> #include <string_view> int main() { std::string_view str{ "balloon" }; // Remove the "b" str.remove_prefix(1); // remove the "oon" str.remove_suffix(3); // Remember that the above doesn't modify the string, it only changes // the region that str is observing. std::cout << str << " has " << std::strlen(str.data()) << " letter(s)\n"; std::cout << "str.data() is " << str.data() << '\n'; std::cout << "str is " << str << '\n'; return 0; } |
all has 6 letter(s) str.data() is alloon str is all
Clearly this isn’t what we’d intended, and is a consequence of trying to access the data() of a std::string_view
that has been modified. The length information about the string is lost when we access data()
. std::strlen
and std::cout
keep reading characters from the underlying string until they find the null-terminator, which is at the end of “balloon”.
Warning
Only use std::string_view::data()
if the std::string_view
‘s view hasn’t been modified and the string being viewed is null-terminated. Using std::string_view::data()
of a non-null-terminated string can cause undefined behavior.
Incomplete implementation
Being a relatively recent feature, std::string_view
isn’t implemented as well as it could be.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
std::string s{ "hello" }; std::string_view v{ "world" }; // Doesn't work std::cout << (s + v) << '\n'; std::cout << (v + s) << '\n'; // Potentially unsafe, or not what we want, because we're treating // the std::string_view as a C-style string. std::cout << (s + v.data()) << '\n'; std::cout << (v.data() + s) << '\n'; // Ok, but ugly and wasteful because we have to construct a new std::string. std::cout << (s + std::string{ v }) << '\n'; std::cout << (std::string{ v } + s) << '\n'; std::cout << (s + static_cast<std::string>(v)) << '\n'; std::cout << (static_cast<std::string>(v) + s) << '\n'; |
There’s no reason why line 5 and 6 shouldn’t work. They will probably be supported in a future C++ version.
![]() |
![]() |
![]() |
hello, I can't seem to get std::string_view to work at all. I have set my compiler to C++17, and even tried the demo for C++20, it just gives this error :
Severity Code Description Project File Line Suppression State
Error (active) E0135 namespace "std" has no member "string_view" examples C:\Users\User\source\repos\examples\examples.cpp 8
I have included <string> and <string_view>, created new repos and updated to above C++17 there too.
Thank you loads in advance!
If you're using Visual Studio and your problem was like mine (saying std has no member string_view) I had to change the C++ Language Standard. I have no idea why or how but for the project I was working on it was set to C++14 for some reason.
Project > Properties > C/C++ > Language >> C++ Language Standard and then you can change it to C++17.
I get similar errors if the solutions platform dropdown box at the Visual Studio top toolbar is x86 instead of x64. (I'm using a 64 bit system.) x86 seems to be the default, so I have to remember to reset it for each new project.
Hi, as far as i'm aware, only std::string and C-style string guarantee null-terminated strings. So how is a string defined with std::string_view is null-terminated like you said here?
`str` is viewing a C-style string ("balloon"). The C-style string is null-terminated.
Hello, I've been experimenting with std::string, and with liberal CPP Reference use, I've coded a text reverser and a pig latin translator. Do these look good to you?
Text Reverser:
Pig Latin Translator:
Hello
Text Reverser
- You don't need to erase anything. You can almost do `temp += str[count];` and remove the `erase` calls.
Pig Latin Translator
- You can do `using std::string;` to use individual namespace members.
- `sub` potentially overflows. You don't need to store all words or characters.
- Doing everything in one function makes your code hard to read. Add functions like `isVowel`, `transformWord`, `getNextWord`.
If you have a `transformWord` function that translates a single word to pig latin, you could use `std::cin`'s space separation behavior to split the input
Thanks for your help!
Text Reverser
Duh! *facepalm*
Pig Latin Translator
Working on it now.
:)
What do you mean by "stored in the binary"? Do you refer to the compiled code file? If so, the strings have to still also be stored somewhere in the memory at least once so the program can use them, right?
Correct. String literals are stored in a section of the binary that gets loaded into memory without doing any modifications to the data. That's the cheapest way of storing values that can't appear in the binary code itself.
Thoughts about explicit / implicit type conversion...
I'm probably just splitting hairs here (and/or maybe this is a borderline case) but in the example below, I would've thought that only the last line would have qualified as an explicit type cast:
Also, I noticed that a direct initialization (with parentheses) also works while the 'normal' copy initialization (with an equals sign) does not:
So, this is kind of interesting. If the code in line 2 would compile, would you consider it an implicit conversion?
Only the last one is an explicit cast, but the `std::string` constructor call is also explicit (We're obviously calling `std::string`'s constructor).
This all gets at `explicit` constructors, which we cover them later in chapter 9. `explicit` constructors disallow copy-initialization, which is why you can't use the equals sign to initialize an `std::string` with a `std::string_view`.
Ah, ok! I'll just keep on reading then :)
Hey Nascardriver,
Thanks for the good tutorials. Its helping me a lot to get in to the C++.
I ran the copy of your code related to the ownership issue. But I am able to print name also from the main function. Seems, it does not go out scope here as we are returning it ?
I even tired with the static array and able to return the string view and print it in the main():
This code causes undefined behavior. It's undefined what happens.
Good tutorial, thank you for your great work! However I got a little confused in this one because although you provide good analogies for how a string_view works, I feel like you don't anywhere explicitly define what a string_view is. One question I had was "can an std::string_view stand on it's own without needing to be assigned an std::string or char array first?" I guess any literal you put in your source code must also have a fixed memory address/value so then that becomes what the string_view is viewing when it gets initialized with a string literal?
Thank you for your feedback!
I updated section "Introducing std::string_view" and "Ownership issues" to address your questions.
A `std::string_view` can stand on its own, but only if it's empty
If no string exists, there's nothing the `std::string_view` can observe.
Awesome, thanks for the clarification!
Hi, when I type
It gives an error : 'string_view' is not a member of 'std'
You need C++17 or higher
I have an impression that string_view is behave like an alias but with "window view" and nothing else. the most usable is still std::string and if we need to mimic "window view" we can use substring function, please cmiimw
i have read quite a few times now that this thing is faster than that thing, like in this chapter C-style strings are faster than std::string, so my question is how is that decided? what makes one thing faster than other? and faster in what sense?
Faster in runtime. Everything you do at runtime takes up time, for example copying a string or creating a string. Your hardware has to work to make these things happen, and that takes time. When you do these things often enough, the time will become noticeable to a human (For example you might get less fps in a video game, or launching the game takes longer).
`name` is a local variable of `getName`, it dies when `getName` ends. The `std::string_view` views `name`, but doesn't extend its lifetime, so `main` is trying to access a variable that's already dead.
In line 12 under the section "std::string_view works with non-null-terminated strings" we do the following:
what is exactly happening here? I understand that we are initializing str with an array, but I don't quite remember seeing this assigning form.
There are different ways of creating a `std::string_view`, one of them is via a data source and a length. `vowels` is the data source and `std::size(vowels)` is the length. We need the length here, because otherwise `std::string_view` would try to determine the length of `vowels` by searching for the null terminator.
https://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view
Thank you very much for the explanation!
Hi, teachers
Say I want to get the size (not length) of the C-string using the string_view, but I get the error
messaging to me "error: no matching function for call to ‘size(const char*&)’" Is there any solution of how to do this? if there will be discussed later in chapters please tell so. Please see the code below
Your question appears to be how to get the length of a C-style string, unrelated to `std::string` and `std::string_view`. If that's not the case, please ask again.
nascardriver,
I understood that by help of data() or c_str() function we can convert string_view to C-style string. C - style string is the array of chars that has the '\0' terminated as it was mentioned in 6.6 lesson. Consequently I could get the size of that array by help of std::size (included in iterator library). But then I get the error instead. So I could presume that realString.c_str() reutrns a type that can't be fed into the std::size. Correct my assumptions please to get the better feeling of understanding.
A C-style string is a `const char*` (Remember, arrays like decaying to pointers). It doesn't hold size information, so `std::size` can't do anything with it.
Unlike C-style strings and std::string, std::string_view doesn’t use null terminators to mark the end of the string. Rather, it knows where the string ends because it keeps track of its length.
and std::string is not null terminated
The internal string of `std::string` can use whatever format it wants. But the internals don't matter in this case. There is no way to access a `std::string` such that it doesn't appear as a null-terminated string.
What is going on with
What is the difference between doing std::string{v} and static casting?
They do the same
Hello again,
Just a minor thing and probably not even that important, but under the section "View modification functions" you include the <cstring> header for the std::strlen function yet it is never used.
Just my 2c.
Keep up the good work!
Hello thanks! I removed the include.
May be you meant "dependent" instead of "independent" under the Ownership Issues section?
Nope, the `std::string_view`'s lifetime is independent of the string it's viewing. The string could live longer or shorter than the `std::string_view`.
I think the combination of that first sentence saying “independent” but then the second sentence explaining how the two are magically intertwined is what is confusing. If the first sentence had an extra “..., but once the original string goes out of scope ..” added to it, then it would be clearer. A std::string_view can’t exist in any meaningful/usable way once the string it is a view for is no longer in scope/existing.
So ...
1. When modifying a C-style string, the std::string_view which is observing that string will get the changes too.
2. But when modifying a std::string, the observing std::string_view will somehow causes undefined behavior.
3. So it is the best to use std::string_view only to observe literal strings.
Do I understand correctly ?
You understand correct. If you know that the `std::string` doesn't change, you can use it in a `std::string_view` too.
I'm a little confused. The following two teaching points seem to contradict each other on the subject of std::string_view and whether it is a null-terminated string. Can you help please?
Unlike C-style strings and std::string, std::string_view doesn’t use null terminators to mark the end of the string. Rather, it knows where the string ends because it keeps track of its length.
// It's okay to use data() because we haven't modified the view, and the
// string is null-terminated.
std::cout << std::strlen(str.data()) << '\n';
Did you mean to write in the commented line that "string is not null-terminated"?
Nope, it's correct as written. Not every `std::string_view` views a null-terminated string. `std::string_view` doesn't modify the string it's viewing. If we initialize it with a string literal (Remember that string literals are null-terminated), then we can safely access `data()`, because it's just a view at out string literal (Which is null-terminated). Though, we have to keep track of this ourselves. If we initialized the `std::string_view` with a char array or let it view only a section of a string, it would not be null-terminated.
>>Being only a view, a std::string_view‘s lifetime is independent of that of the string it is viewing. If the viewed string goes out of scope, std::string_view has nothing to observe and accessing it causes undefined behavior.
Dependent instead of independent ?
A std::string_view has an independent lifetime from the string it's viewing (e.g. a std::string_view can outlive the string it's viewing, at which point, it becomes invalid).
A std::string_view validity is dependent on the string it's viewing (e.g. a std::string_view becomes invalid when the string it's viewing dies).
std::string_view's function seems to overlap a lot with what constant references are used for. Why is it preferred?
I suppose you mean a const reference to a `std::string`.
`std::string` can't be used at compile-time, as it requires dynamic memory allocation. Also, if you use a `std::string`, you have to create it first before you can bind a reference to it. Creating the `std::string` creates a copy of the string literal, which might be undesired.
Good day everybody!!!
Wanted to clarify one thing.
The following code works just fine even though i don't include string or string_view
Please see https://www.learncpp.com/cpp-tutorial/header-files/#missing_include_but_works
Thanks vary much!
I somehow missed this section
Hi, Under Opening the window (kinda) via the data() function:
how do we know std::string_view str{ "balloon" }; is null-terninated string?
From what i understood is it because all strings(refers to group of characters here) default to null-terminated strings? If the characters are separated by "," they naturally default to non-null-terminated and c-style, which can only be printed to screen by converting them to std::string_view like in vowels example ? Is it correct ?
"balloon" is a string literal, string literals are zero-terminated. If you have an array of characters, then that array isn't zero-terminated (unless you added a terminator).
Thank you, we add an terminator to array of characters like this right??
Here it prints 0 after aeiou but its not shown in output right ?
Right. When you print a 0-valued byte, you see nothing. You could print the array without a loop, because now `std::cout` can know where the string ends.
Then, can I ask a C-style string, and string literals are null-terminated, whether string or string_view's variable are not???
It doesn't matter if `std::string` is zero-terminated. The only way to access its internal string is via `.data()` and `.c_str()`, both of which are guaranteed to return a zero-terminated string.
`std::string_view` is not zero-terminated, because it's just a view onto another string. It has no influence on the string's data, so the only way to reliably know where the string ends is by storing the string's length. This allows `std::string_view` to shrink the viewed string without modifying it (It simply reduces the length).
[code]
char arr[]{ "Gold" };
char name[] = "Jason";
[code]
I learned in lesson 6.8 that I haven't got '\0' at the end of "Gold" but got one with "Jason". Is the assignment initialisation better?
Both arrays are zero-terminated
Output
5
5
Lesson 6.6 says so. I couldn't find anything stating the opposite in lesson 6.8. If there's misinformation in lesson 6.8, please point it out as to not confuse other readers.
So basically, std::string_view is kinda incomplete, and should only be used when we need constant strings at this point if I understand correctly?
Correct. If you're not going to modify a string and you can initialize it, use a `std::string_view`.
Hi, I think there is a missing parenthesis in the third code example for the substr call.
It was missing indeed. Thanks for pointing out the omission!
Minor typo: In "When you use a std::string_view, it’s best to avoid modifications the to underlying string," "the" and "to" seem swapped.
OK. I saw that the first example has been modified to use char[] instead of const char *, but then should there also be a copy of the string allocated on the stack frame of main()?
Right, I missed that when updating the lesson to use `char[]`, thanks for pointing it out!.
Then it comes up to 4 copies of the string?
I don't think so. When you have 1 paper and copy it, you have 2 papers but only 1 copy, right?
The string is there 4 times, but only 3 of the strings are copies. That's how I look at it, I don't know if it's correct.
In C++, the term "copies" is often used to mean the "number of" something. So if you have a string, and you copy it, you now have two copies of that string.
I think it's more correct to say that the first program has 4 copies of the string -- but function main only creates 3 of those copies. Perhaps the text should be amended to say, "main creates 3 copies" rather than "this program creates 3 copies"? That way we avoid the ambiguity about whether the string in read-only memory counts as a "copy" or not.
Updated to "main copies the string “hello” 3 times, resulting in 4 copies"
So, just to make it clear: if by "copy" we mean data allocated in the memory, are you saying the first program is using four separate memory locations: one for the literal, one for the char[] and one for each string? Literals use memory?! I don't really undertand how strings hold copies while char[] don't, sorry.
> are you saying the first program is using four separate memory locations: one for the literal, one for the char[] and one for each string?
Yes.
> Literals use memory?
Yes, they have to be stored somewhere.
> I don't really undertand how strings hold copies while char[] don't
This should clear up when you learn about pointers. If you still have questions then, just ask.
when I'm trying to compile this code , the compiler complain that
'string_view': is not a member of 'std'
[/
#include <iostream>
#include <string_view>
int main()
{
std::string_view text{ "hello" }; // view the text "hello", which is stored in the binary
std::string_view str{ text }; // view of the same "hello"
std::string_view more{ str }; // view of the same "hello"
std::cout << text << ' ' << str << ' ' << more << '\n';
return 0;
}
]
Hi!
`std::string_view` was added in C++17. Make sure you enabled C++17 or higher in your project settings.
For future readers, setting C++17 (or higher) is now covered in lesson 0.12.
Thank you very much
Hey nascardriver,
From the start of this article, you introduce "const char*" to define strings but I don't think we have already seen what it is and what it does earlier in the tutorial. Is it like using "std::string" ?
Another thing is I have played around a bit with std::string_view and there are some pretty bizarre behaviours, like in the following code :
This prints :
Hello Hello
Hi Hilo
What is happening here ? Maybe this could be explained in the article as well ?
Cheers
Update : I've advanced to lesson 6.8b and the syntax "const char*" is explained there (C-style string symbolic constants). Maybe this lesson on std::string_view should be moved further down the chapter ?
> you introduce "const char*" to define strings but I don't think we have already seen what it is
It's a `const char[]` with a different syntax, I though it was a part of the previous lesson, but it isn't. I changed every `const char*` to `char[]` or "C-style string". Thanks for letting me know!
> like in the following code
I wanted to include an example that shows that `std::string_view` reflects the changes made to its underlying string, but I'd have to move this lesson further back, which I don't want to do, because it would motivate the use of C-style strings.
Your code invokes undefined behavior (I added a paragraph to the lesson).
When you assign "Hi" to `str` in line 8, `str`'s old string "Hello" can be invalidated. In your case, since "Hi" is shorter than "Hello", the `std::string` re-used the memory it was using the store "Hello". That memory is now "Hi\0lo" (\0 is a null-terminator).
If you assigned something longer, the old string could die completely.
`view` still looks at where the old string was, but `view`'s size isn't changed (The curtains are where they were before). Since `std::string_view` doesn't use null-terminators, the \0 is ignored and "Hilo" is printed.