Reputation: 3550
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
Upvotes: 10
Views: 9657
Reputation: 11178
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
}
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.
Upvotes: 14
Reputation: 238491
Don't return a string view when:
Do realise, that the string view becomes invalidated by operations on the original string such as changing the capacity, as well as if the original string is destroyed. If the caller needs the string for a longer than the life time of the object that stores the string, then they can copy from the view into their own storage.
Upvotes: 6