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

2
  • 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? Commented Nov 29, 2021 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. Commented Nov 29, 2021 at 22:09

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

7 Comments

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 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.
@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.
@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.
@digito_evo To clarify a bit, there is no difference within iss nor stoi. The difference - if any - is in the string constructor.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.