I understand the motivation for using std::string_view;
it can help avoid unecessary allocations in function arguments.
For example:
The following program will create a std::string
from a string literal.
This causes an undesired dynamic allocation, as we are only interested observing the characters.
#include <iostream>
void* operator new(std::size_t n)
{
std::cout << "[allocating " << n << " bytes]\n";
return malloc(n);
}
void observe_string(std::string const& str){}
int main(){
observe_string("hello world"); //prints [allocating 36 bytes]
}
Using string_view
will solve the problem:
#include <iostream>
#include <experimental/string_view>
void* operator new(std::size_t n)
{
std::cout << "[allocating " << n << " bytes]\n";
return malloc(n);
}
void observe_string(std::experimental::string_view const& str){
}
int main(){
observe_string("hello world"); //prints nothing
}
This leaves me with a question.
When would I choose std::string by const& instead of string_view for function arguments?
Looking at the interface of std::string_view
, it looks as though I could replace all instances of std::string
that are passed by const&
. Are there any counter examples to this? Is std::string_view
meant to replace std::string const&
for parameter passing?
It's wrong. Passing the arguments of basic types (int, float, char....) is more effecient than passing them by reference. const & is more effecient in passing the BIG OBJECT. Because the reference is a alias of a object in essential, the compiler need to handle more information.
Pass Using Const Reference in C++ Now, we can use the const reference when we do not want any memory waste and do not change the variable's value. The above code will throw a compile error as num = num +10 is passed as a const reference.
Passing a parameter by const reference should be chosen where the semantics of references are actually required, or as a performance improvement only if the cost of potential aliasing would be outweighed by the expense of copying the parameter. At times, copying your parameters can also give you locality benefits.
- const references allow you to specify that the data referred to won't be changed. A const reference is actually a reference to const. A reference is inherently const, so when we say const reference, it is not a reference that can not be changed, rather it's a reference to const.
When would I choose
std::string
byconst&
instead ofstring_view
for function arguments?
Do you need a null-terminated string? If so, then you should use std::string const&
which gives you that guarantee. string_view
does not - it's simply a range of const char
.
If you do not need a null-terminated string, and you do not need to take ownership of the data, then you should use string_view
. If you do need to take ownership of the data, then it may be the case that string
by value is better than string_view
.
One possible reason to accept const std::string&
instead of string_view
is when you want to store reference to string object which can change later.
If you accept and store a string_view
, it might become invalid when string
internal buffer reallocates.
If you accept and store reference to string itself, you won't have that problem, as long as that object is alive (you probably want to delete r-value reference overload, to avoid obvious problem with temporaries).
Andrei Alexandrescu once said, "No Work is better than some work". So you should use const std::string&
in such contexts. Because std::string_view
still involves some work (copying a pair of pointer and length).
Of course, const references may still have the cost of copying a pointer; which is almost the equivalent of what std::string_view
will do. But there's one additional work with std::string_view
, it also copies the length.
This is in theory, but in practice, a benchmark will be preferred to infer performance
It is not really what you were asking, but sometimes you want to take std::string
by value rather than std::string_view
for performance reasons. This is the case when you will need to modify the string before inspecting it:
bool matches(std::string s)
{
make_upper_case(s);
return lib::test_if_matches(s);
}
You need a mutable string somewhere anyway, so you may declare it as function parameter. If you changed it to to std::string_view
, and somebody passes an std::string
to function matches()
you would be first converting string
to string_view
and then string_view
to string
, and therefore allocating twice.
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