68

Compiling with gcc-7.1 with the flag -std=c++17, the following program raises an error:

#include <string_view>
void foo(const char* cstr) {}
void bar(std::string_view str){
    foo(str);
}

The error message is

In function 'void bar(std::string_view)':
error: cannot convert 'std::string_view {aka std::basic_string_view<char>}' to 'const char*' for argument '1' to 'void foo(const char*)'
 foo(str);

I'm surprised there is no conversion to const char* because other libraries (abseil, bde), provide similar string_view classes which implicitly convert to const char*.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Justin Raymond
  • 3,413
  • 2
  • 19
  • 28
  • 1
    My mistake, [`std::std::basic_string_view::data`](http://en.cppreference.com/w/cpp/string/basic_string_view/data) does not guarantee a null terminated string. – François Andrieux Jan 03 '18 at 16:36

4 Answers4

93

A std::string_view doesn't provide a conversion to a const char* because it doesn't store a null-terminated string. It stores a pointer to the first element, and the length of the string, basically. That means that you cannot pass it to a function expecting a null-terminated string, like foo (how else are you going to get the size?) that expects a const char*, and so it was decided that it wasn't worth it.

If you know for sure that you have a null-terminated string in your view, you can use std::string_view::data.

If you're not you should reconsider whether using a std::string_view in the first place is a good idea, since if you want a guaranteed null-terminated string std::string is what you want. For a one-liner you can use std::string(object).data() (note: the return value points to a temporary std::string instance that will get destroyed after the end of the expression!).

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • The explanation for why std::string_view doesn't provide a conversion is great, but only offers a provisional answer to the question. – Syndog Jan 01 '19 at 14:11
  • 1
    Your recommendation about `std::string(object).data()` is a bad one, because in most cases the data will point to unallocated storage. – rems4e Feb 21 '20 at 19:59
  • 12
    @rems4e An alarm went off for me as well when I saw `std::string(object).data()` recommended without the important caveat that the returned pointer is to data inside the temporary std::string object, which lasts only til the end of the largest enclosing expression. – Don Hatch Apr 02 '20 at 07:02
  • 2
    Please remove `std::string(object).data()` from the answer or provide an easily visible warning. The `std::string(object)` here gets deallocated, so the resulting C string is undefined. I've seen this snippet being pasted all over the internet and in various code bases. This answer has caused an immense amount of damage. – 23scurtu Sep 07 '21 at 21:47
56

Simply do a std::string(string_view_object).c_str() to get a guaranteed null-terminated temporary copy (and clean it up at the end of the line).

This is required because string view doesn't guarantee null termination. You can have a view into the middle of a longer buffer, for example.

If this use case is expensive and you have proven it to be a bottleneck, you can write an augmented string_view that tracks if it is null terminated (basically, if it was constructed from a raw char const*).

Then you can write a helper type that takes this augmented string_view and either copies it to a std::string or stores the augmented string_view directly, and has an implicit cast-to-char const* that returns the properly null-terminated buffer.

Then use that augmented helper type everywhere in your code base instead of string_view, possibly augmenting string view interaction with std string as well to catch the cases where you have a view that goes to the end of the std string buffer.

But really, that is probably overkill.

A better approach is probably rewriting the APIs that take const char* to take string_view.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 2
    by " (and clean it up at the end of the line).", I can continue use the member of that Rvalue til the end of scope that `std::string(string_view_object).c_str()` sitting, right? – sandthorn Jan 30 '18 at 10:28
  • 2
    @sandthorn No, until the end of the full expression, not scope. – Yakk - Adam Nevraumont Jan 30 '18 at 14:25
  • 1
    @sandthorn If you want the string to stick around, you'd maybe prefer `std::string TempVar(string_view_object);` then where you need it in scope, `TempVar.c_str()`. – Ruzihm Feb 24 '21 at 08:10
11

You can call foo(std::string(str).c_str()).

0

using object.data() solved my problem with compiler error C2664

werber bang
  • 173
  • 3
  • 11
  • 1
    Are you sure you haven't introduced a bug? Please see the other answers. – Bob__ Nov 30 '22 at 09:03
  • for my case I needed a pointer to the beginning of the string_view , I was using begin() instead of data() , which resulted in error C2664, and then I chcanged that to data() instead but not sure if that introduces a bug, can you please give more details? – werber bang Dec 01 '22 at 08:38
  • It depends on *your* use case. OP's one is to pass an entire `string_view` to a function accepting *only* a `const char*`. Those functions *usually* expect **null-terminated** arrays of `char` and that isn't guaranteed by `std::string_view::data()`, unlike `std::string::data()` (since C++11). – Bob__ Dec 01 '22 at 09:09
  • 2
    You should not do that! `std::string_view` does not guarantee that string it posints to is null-terminated. Just do `static_cast(object).c_str()` Yes, temporary copy. But safe and with null-termination – Ihor Baklykov Dec 28 '22 at 15:28