I'm writing some communication application. Before C++17 (without Boost), I use std::string
and its const reference as cls1
.
Since C++17, I introduced std::string_view
to my code as cls2
.
However, I don't have clear policy when should I use std::string_view
. My communication application receives data from the network and it is stored to recv_buffer
. And creates some application classes from recv_buffer
.
If I focus only cls1
's constructor, move construction is efficient. But I think that where the parameter s
from. If it is originally from the recv_buffer
, I can create std::string_view
at the receiving (very early) point. And during recv_buffer
's lifetime is enabled, use std::string_view
everywhere. If I need to store the part of recv_buffer
then create std::string
.
An only exception I noticed is the recv_buffer
is always contained complete data for my application class. In this case, move construction is efficient.
I think using the return type as std::string_view
has advantage. Some member function such as substr()
is efficient. But I don't see any disadvantage, so far.
I suspect that I might see only pros of std::string_view
. Before re-writing many codes, I would like to know your ideas.
#include <string>
struct cls1 {
explicit cls1(std::string s):s_(std::move(s)) {}
std::string const& get() const { return s_; }
private:
std::string s_;
};
struct cls2 {
explicit cls2(std::string_view s):s_(s) {}
std::string_view get() const { return s_; }
private:
std::string s_;
};
#include <iostream>
int main() {
// If all of the receive buffer is the target
{
std::string recv_buffer = "ABC";
cls1 c1(std::move(recv_buffer)); // move construct
std::cout << c1.get().substr(1, 2) << std::endl; // create new string
}
{
std::string recv_buffer = "ABC";
cls2 c2(recv_buffer); // copy happend
std::cout << c2.get().substr(1, 2) << std::endl; // doesn't create new string
}
// If a part of the receive buffer is the target
{
std::string recv_buffer = "<<<ABC>>>";
cls1 c1(recv_buffer.substr(3, 3)); // copy happend and move construct
std::cout << c1.get().substr(1, 2) << std::endl; // create new string
}
{
std::string recv_buffer = "<<<ABC>>>";
std::string_view ref = recv_buffer;
cls2 c2(ref.substr(3, 3)); // string create from the part of buffer directly
std::cout << c2.get().substr(1, 2) << std::endl; // doesn't create new string
}
}
Running Demo: https://wandbox.org/permlink/TW8w3je3q3D46cjk
string_view is useful when you want to avoid unnecessary copies. String_views are less memory-intensive to construct and copy. The creation of string_view from literals does not require a dynamic allocation.
The std::string_view, from the C++17 standard, is a read-only non-owning reference to a char sequence. The motivation behind std::string_view is that it is quite common for functions to require a read-only reference to an std::string-like object where the exact type of the object does not matter.
So, frequently, you can pass string_view by reference and get away with it. But you should pass string_view by value, so that the compiler doesn't have to do those heroics on your behalf. And so that your code-reviewer doesn't have to burn brain cells pondering your unidiomatic decision to pass by reference.
std::string class in C++ C++ has in its definition a way to represent a sequence of characters as an object of the class. This class is called std:: string. String class stores the characters as a sequence of bytes with the functionality of allowing access to the single-byte character.
std::string_view
is a way to get some std::string
const member functions without creating a std::string if you have some char*
or you want to reference subset of a string.
Consider it as a const reference. If the object it refers vanishes (or changes) for any reason, you have a problem. If your code can return a reference, you can return a string_view.
Example:
#include <cstdio>
#include <string>
#include <vector>
#include <string.h>
#include <iostream>
int main()
{
char* a = new char[10];
strcpy(a,"Hello");
std::string_view s(a);
std::cout << s; // OK
delete[] a;
std::cout << s; // whops. UD. If it was std::string, no problem, it would have been a copy
}
More info.
Edit: It doesn't have a c_str()
member because this needs the creation of a \0 at the end of the substring which cannot be done without modification.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With