# string_view in functions that require a c-string?

This topic is 414 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi,

I've recently starting porting my codebase towards using std::string_view, which is part of the new C++17-standard. I've actually implemented my own version of it, which might be important later when talking about the problem I now face.

So at first it seemed really straight-forward, just replace pretty much every occurance of "const std::string&" with "sys:StringView", except for places where I can take advantage of move-semantics. But then I ran into issues, at places where functions from the standard c-library/WinAPI were being called, like this:

 void copy(sys::StringView stInName, sys::StringView stOutName)
{
std::ifstream ifs(stInName.Data(), std::ios::binary);
std::ofstream ofs(stOutName.Data(), std::ios::binary);

if(!ifs.is_open())
throw fileException();
else if(!ofs.is_open())
throw fileException();

ofs << ifs.rdbuf();
}

Oups, std::ifstream expects a null-terminated c-string, and sys::StringView can (and often will) point to a portion of a char-array that is not null-terminated, ie. if a Substr() is generated from another stringview. This obviously means subtle fails when trying to open a file, convert a string to an int, etc... as the function will ignore the size stored in the string-view, and will continue to read characters until the end of the actual string.

Now my question to those who have already used std::string_view, or just had a thorough thought about it: How would you solve this situation? The premise is to use std::string_view as much as possible due to the inherent benefits not only for speed but also for clearity. The ideas I so far had:

- Just pass "const std::string&" to the functions expecting a c-string. Pretty messy, as most other code uses or generates StringViews, which means I have to manually convert to std::string whenever I call such an function.

- Before a call that expects a c-string, convert StringView to std::string and use that. While it technically shouldn't matter as most of the calls requiring a c-string are expensive by themselves, it kind of defeats the purpose of using the StringView in the first place, and actually make some functions slower then if I were just passing a "const std::string&".

- Make a "CStringView" class the always has to point to a null-terminated string. Would be the same as StringView, except it can only be created from an std::string or const char* directy. This would then be used for functions that require a c-string. I've tried it a bit but ran into problems with functions like the one above that are called from many different places with different data, especially when being used in my data-driven content pipeline, since its not trivial to make sure that when I call the function, I actually have a null-terminated string anymore.

- Make an "ToAPI"-function, which looks like this:

template<size_t Size>
std::array<Type, Size> _ToAPI(void) const
{
std::array<Type, Size> vArray;

CopyInto(vArray.data(), Size);
vArray[Size()] = '\0';

return vArray;
}

This actually saves the dynamic allocations made by converting to a string (and hopefully the array would benefit from copy-ellision/RVO), though it cannot be used with every type of string, since you have to specific the max-size beforehands. This is actually the solution I went with right now, as it allows me to hide the requirement for a real c-string on the callees side, should have a neglectible performance overhead and be somewhat safe (I can add checks that the string doesn't surpass the specified size). In addition, I'm rewriting most simpler functions that usually require a c-string (atoi, _strtoi64, ...) so they can work directly with my StringView-class.

Though I'm still not 100% happy, and wondering if there are any other options. So what did/would you do? Any one or combination fo the above; or something entirely different? Seeing how string_view is actually designed without a guarantee for 100% safety, I'm still "shocked" at how difficult things can get when interacting with "outdated" APIs...

##### Share on other sites

Looks to me like the only reasonable approach is to convert to std::string when you need to hit a C-style API. They want a fundamentally different type to the one that a string view provides and that is the end of it really. The string view is still useful for all the times when you don't reach an old-style API. Obviously if I then found specific parts of my code where this was not fast enough, I might then consider the std::array solution or similar.

Of course, if most of your code paths do end up wanting a null-delimited char* in the end, the string view is probably the wrong approach for this project.

##### Share on other sites
35 minutes ago, Kylotan said:

Looks to me like the only reasonable approach is to convert to std::string when you need to hit a C-style API. They want a fundamentally different type to the one that a string view provides and that is the end of it really. The string view is still useful for all the times when you don't reach an old-style API. Obviously if I then found specific parts of my code where this was not fast enough, I might then consider the std::array solution or similar.

Hm, yeah, makes sense to me I suppose. Speed shouldn't really shouldn't be an issue for all the code paths where I need a c-string, as those functions are usually expensive by themselves. I'm just a bit bummed that I ran into issues like that. There's a lot of other little inconveniences too, like heterogenous lookup in unordered containers and so on.

I just hope that at least the STL will be updated to make better use of string-views/strings with known length, I mean after all std::string_view is being implemented so why not fully make use of it?

40 minutes ago, Kylotan said:

Of course, if most of your code paths do end up wanting a null-delimited char* in the end, the string view is probably the wrong approach for this project.

Nah, that shouldn't be the case. Its mostly in my file IO & string-conversion wrappers, where the issue is rather that I just cannot reason about when and how a function like "copyFile" is being called. Other than that, using string view has paid of so far - except for the fact that it took 4 days so far integrating it in the base systems w/o being able to compile - good thing I'm not on a time-constraint or anything.

1. 1
2. 2
3. 3
4. 4
5. 5
Rutin
11

• 12
• 16
• 9
• 14
• 10
• ### Forum Statistics

• Total Topics
632659
• Total Posts
3007688
• ### Who's Online (See full list)

There are no registered users currently online

×