How you convert a std::string_view to a const char*?

49,217

Solution 1

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

Solution 2

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.

Solution 3

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

Share:
49,217

Related videos on Youtube

Justin Raymond
Author by

Justin Raymond

Updated on January 07, 2022

Comments

  • Justin Raymond
    Justin Raymond over 2 years

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

  • sandthorn
    sandthorn over 6 years
    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?
  • Yakk - Adam Nevraumont
    Yakk - Adam Nevraumont over 6 years
    @sandthorn No, until the end of the full expression, not scope.
  • Syndog
    Syndog over 5 years
    The explanation for why std::string_view doesn't provide a conversion is great, but only offers a provisional answer to the question.
  • rems4e
    rems4e over 4 years
    Your recommendation about std::string(object).data() is a bad one, because in most cases the data will point to unallocated storage.
  • Don Hatch
    Don Hatch about 4 years
    @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.
  • Ruzihm
    Ruzihm over 3 years
    @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().
  • 23scurtu
    23scurtu over 2 years
    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.
  • Sahsahae
    Sahsahae about 2 years
    It is really sad that on stack overflow we're so concerned about idiots who follow cargo cult to the T and copy paste from stack overflow for a living instead of using their brain. I don't understand, how this is even worth a consideration? You either need to pass a temporary string to some function that will do something with it for a bit, or you don't. And given the question, it is perfectly acceptable. Why should anyone care if some idiot can't read and copy pastes blindly things he doesn't even understand? Such idiot shouldn't have a job in the first place, not be shielded by SO answers.