28

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?

Trevor Hickey
  • 31,728
  • 22
  • 131
  • 236
  • I was going to say: if the function was going to stash away the parameter into a discrete std::string internally, then copy-construction would be cheaper than string-to-string-view-to-string round-trip. But I realized that basic_string_view could memorize that it was constructed from a string, and just return the same one from its to_string() method. – Sam Varshavchik Sep 19 '16 at 02:27
  • @SamVarshavchik: If you're gonna make a copy, you want to accept the argument by value so it can be either copy- or move-constructed. – GManNickG Sep 19 '16 at 02:53
  • If you're going to pass the parameter along to something that only takes a string, such as `ifstream`'s constructor or `operator+` (see [this question](https://stackoverflow.com/questions/44636549/why-is-there-no-support-for-concatenating-stdstring-and-stdstring-view)) then you might as well take it as a `const string &`. (I suppose this is just a complicated way of saying "When you really need a `string`.) – Chris Hartman Apr 18 '18 at 17:06

4 Answers4

16

When would I choose std::string by const& instead of string_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.

Barry
  • 247,587
  • 26
  • 487
  • 819
  • 4
    For clarification: needing my string null-terminated means that the `std::string` underlying `char`-array should end in `\0`, right? Hard to imagine someone needs this when using `std::string` already. Its like mixing C with modern C++, or am I wrong? – M. Winter Aug 13 '17 at 16:52
  • If one needs a NTBS, I think they may just use `const char*` as the parameter type. – cpplearner Aug 13 '17 at 17:28
  • 4
    @M.Winter It's pretty easy to imagine... there's plenty of APIs that require null-terminated strings. – Barry Aug 13 '17 at 22:57
7

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).

Revolver_Ocelot
  • 7,747
  • 3
  • 26
  • 45
4

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


WhiZTiM
  • 19,970
  • 3
  • 36
  • 56
2

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.

Andrzej
  • 4,435
  • 23
  • 32