0

Is a std::string_view parameter better than a const char* one in the code below?

void func( const std::string_view str )
{
    std::istringstream iss( str.data( ) ); // str is passed to the ctor of istringstream


    std::size_t pos { };
    int num { std::stoi( str.data( ), &pos, 10 ) }; // and here it's passed to std::stoi
}

int main()
{
    std::array<char, 20> buffer { };
    std::cin.getline( buffer.data( ), 20 );
    func( buffer.data( ) );
}

Both std::istringstream ctor and std::stoi require a const std::string& as their parameter. But I pass them a std::string_view object using its data() member function. Is this bad practice? Should I revert back to const char*?

digito_evo
  • 3,216
  • 2
  • 14
  • 42
  • 1
    It should be possible to figure out the answer simply by reading `std::string_view`'s documentation, specifically its constructors' documentation, and taking a moment to think what it means, for the constructor to work that way. Based solely on the public specifications of the constructors of all the objects referenced in the shown code it should be fairly straightforward to determine what's happening, and whether or not there is any improvement by avoiding the use of `string_view` and passing a plain pointer instead. Have you tried working everything out, like this, with pen and paper? – Sam Varshavchik Nov 29 '21 at 22:07
  • 2
    Consider `std::string{str}` instead of `str.data( )` for constructing `std::istringstream iss`. You are constructing a `std::string` in both cases, but `str.data()` will cause problems if there is no null-terminating byte. – Drew Dormann Nov 29 '21 at 22:09

1 Answers1

5

But I pass them a std::string_view object using its data() member function. Is this bad practice

Yes, this is a bad practice. It's bad primarily because a string view doesn't necessarily point to a string that is null terminated. In case it doesn't, passing data() into a function that requires null termination will result in undefined behaviour.

Secondarily, there are cases where knowing the length of the string beforehand is more efficient. The length is known since it's stored in the string view. When you use data() only as an argument, you're not providing the known size to the function.

Use this instead: std::istringstream iss(std::string{str});

Should I revert back to const char*?

I see no good reason for doing so in this case.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `std::cin.get` receives the user's string and null terminates it as far as I know. So I don't worry about that. But is `std::istringstream iss(std::string{str});` as efficient as passing a `const char*`? I mean it creates a temporary `std::string`. – digito_evo Nov 29 '21 at 22:16
  • @digito_evo `std::cin.get receives the user's string and null terminates it as far as I know.` What does that have to do with `func`? Nothing prevents `func` from being called with a string that wasn't received with `std::cin.get`. – eerorika Nov 29 '21 at 22:17
  • @digito_evo `But is std::istringstream iss(std::string{str}); as efficient as passing a const char*?` Measure it and find out. I would predict any difference to be less than the noise. – eerorika Nov 29 '21 at 22:19
  • Right. `func` can receive a non-null terminated buffer. Sounds dangerous. – digito_evo Nov 29 '21 at 22:21
  • My real question is that since std::string_view holds the size of the underlying buffer, does passing it to `iss` ctor the way you showed, have any benefits? I mean will it prevent `iss` from reallocating its internal buffer? cause the user's buffer is 169 chars in my program. Will `iss` first check the size of `std::string{str}` and then allocate at least 169 bytes to its internal buffer at the begging of `iss`s construction? Also how can this affect `stoi`s performance? Should I do the same thing for that too? – digito_evo Nov 29 '21 at 22:27
  • 2
    @digito_evo `does passing it to iss ctor the way you showed, have any benefits?` Maybe in theory. But that doesn't mean that the difference is enough to be measurable. `I mean will it prevent iss from reallocating its internal buffer?` I wouldn't assume that iss would need to reallocate regardless. `Will iss first` You can check the source to verify. I see no reason why it couldn't. `Also how can this affect stois performance?` Potentially in same way. `Should I do the same thing for that too?` Yes, you're still constructing a string and `data()` may lead to UB. – eerorika Nov 29 '21 at 22:32
  • 1
    @digito_evo To clarify a bit, there is no difference within `iss` nor `stoi`. The difference - if any - is in the string constructor. – eerorika Nov 29 '21 at 22:37