What I'm trying to do is have my class accept a string during construction. I read that string_view
was a replacement for const string&
so naturally I wrote a constructor like this. This allows me to accept c++ and c strings.
Url::Url(boost::string_view raw_url)
: url_(static_cast<std::string>(raw_url)) {
The problem which might be here is that when an rvalue is passed, there is a unnecessary copy instead of a move. Is the solution to make another constructor which takes string&&
? What is the best practice here?
Note: I'll write the answer considering std::string_view
, but boost::string_view
should be similar.
I read that string_view was a replacement for const string&
It is useful to understand the reason why std::string_view
was added in the first place.
What is the problem with const string&
?
It is certainly efficient if you pass an std::string
object and you don't gain anything with std::string_view
. But suppose now that you are passing a char*
containing a large string. In that case a temporary std::string
object will be created (and the whole string referenced by that char*
will be copied) just so the function receives an std::string
. That is when std::string_view
shines. If you pass a char*
or a std::string
(or anything that can be converted to std::string_view
) to a function accepting std::string_view
(by value, no need to accept a std::string_view
by reference) then the new std::string_view
object that is created is very cheap, since it is only "a view" and it does not copy the underlying string.
But your case is different. Since you are copying the string anyway, then your function should just accept a string by value and move the string inside the function. Something such as
Url::Url(std::string raw_url)
: url_(std::move(raw_url)) {
There is even a clang-tidy warning to tell you this.
The advantage is that if the user of your function pass an lvalue you make a copy (you need it anyway) and a move, but if they pass an rvalue then there is no copy and only a move.