How to handle NULL string for UTF conversion function
Hi, in my work on Boost.Nowide I encountered a valid NULL string and am unsure how to handle it. Context: Every wrapper functions is basically implemented like: int fFOO(const char* s){ wstackstring const ws(s); // Converts UTF-8 to wchar-buffer/string return _wfFoo(ws.c_str()); } Similar functions like `std::wstring widen(string-or-const-char-ptr)` are provided which can be used like `return _wfFoo(widen(s).c_str());` in the example above. All was fine, because (IIRC) calling e.g. `fopen(NULL)` is not allowed anyway. However `freopen` DOES allow a NULL for the string. So now I'm left with a couple options and would like some opinions on them: 1. Make (w)stackstring aware of NULL input and if default constructed or with NULL return NULL for c_str(). Makes it easy to use as one could even say `return _wfFoo(wstackstring(s).c_str());` w/o any checks but would be inconsistent with the `widen` functions which convert the passed pointer into a std::(w)string and hence require != NULL 2. Disallow NULL (via assert) for all conversions and require manual checking. Best usage would then probably be to ditch the temporary and do `return _wfFoo(s ? wstackstring(s).c_str() : NULL);` 3. Just like 1. but rename (w)stackstring to e.g. (w)cstring (or ncstring/wcstring, or narrow_cstring/wide_cstring) to highlight that it acts like a C-String (and can be NULL as opposed to empty but never NULL) 4. Ditch stackstring entirely. It was complained about by Zach during the review although defended by the author as "stackstring is barely on-stack buffer optimization - it isn't general string and never intended to be so. It isn't in details because it can actually be useful outside library scope." So this would worsen performance a bit as usual SSO are to small for common filenames. Thanks for reading and any insight is welcome! Alex
On Tue, Dec 3, 2019 at 4:06 PM Alexander Grund via Boost
Hi,
in my work on Boost.Nowide I encountered a valid NULL string and am unsure how to handle it.
Context: Every wrapper functions is basically implemented like: int fFOO(const char* s){ wstackstring const ws(s); // Converts UTF-8 to wchar-buffer/string return _wfFoo(ws.c_str()); }
Similar functions like `std::wstring widen(string-or-const-char-ptr)` are provided which can be used like `return _wfFoo(widen(s).c_str());` in the example above.
All was fine, because (IIRC) calling e.g. `fopen(NULL)` is not allowed anyway.
However `freopen` DOES allow a NULL for the string. So now I'm left with a couple options and would like some opinions on them:
1. Make (w)stackstring aware of NULL input and if default constructed or with NULL return NULL for c_str(). Makes it easy to use as one could even say `return _wfFoo(wstackstring(s).c_str());` w/o any checks but would be inconsistent with the `widen` functions which convert the passed pointer into a std::(w)string and hence require != NULL
I think if input is nullptr than output can be nullptr as well. Artyom
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 4/12/2019 09:50, Artyom Beilis wrote:
I think if input is nullptr than output can be nullptr as well.
Mostly this, when both sides are pointers. If one is a string type, so that you can't represent nullptr, then there's a couple of choices: 1. Use optional<string> so that you can explicitly represent the null state. This also acts as a hint to the user that the method has some special handling for the null case. 2. Treat an empty string as equivalent to nullptr. This would usually be safe (an empty filename is usually illegal, although an empty directory name is not). Either way will probably require conditional logic to bypass the normal conversion.
On 12/3/2019 9:06 AM, Alexander Grund via Boost wrote:
Hi,
in my work on Boost.Nowide I encountered a valid NULL string and am unsure how to handle it.
Context: Every wrapper functions is basically implemented like: int fFOO(const char* s){ wstackstring const ws(s); // Converts UTF-8 to wchar-buffer/string return _wfFoo(ws.c_str()); }
Similar functions like `std::wstring widen(string-or-const-char-ptr)` are provided which can be used like `return _wfFoo(widen(s).c_str());` in the example above.
All was fine, because (IIRC) calling e.g. `fopen(NULL)` is not allowed anyway.
However `freopen` DOES allow a NULL for the string. So now I'm left with a couple options and would like some opinions on them:
1. Make (w)stackstring aware of NULL input and if default constructed or with NULL return NULL for c_str(). Makes it easy to use as one could even say `return _wfFoo(wstackstring(s).c_str());` w/o any checks but would be inconsistent with the `widen` functions which convert the passed pointer into a std::(w)string and hence require != NULL
Never return NULL from c_str(), as opposed to a C pointer to an empty C string. Nobody else has ever done this, no one will expect it, and it will just confuse users who deal with other string objects which have a c_str() function.
2. Disallow NULL (via assert) for all conversions and require manual checking. Best usage would then probably be to ditch the temporary and do `return _wfFoo(s ? wstackstring(s).c_str() : NULL);`
Sounds best. It's C++ and NULL is C. Forget about C. The library I take it will soon be in Boost and be for C++ users.
3. Just like 1. but rename (w)stackstring to e.g. (w)cstring (or ncstring/wcstring, or narrow_cstring/wide_cstring) to highlight that it acts like a C-String (and can be NULL as opposed to empty but never NULL)
Waste of time. No matter what it is called returning NULL as opposed an empty string from c_str() is just wrong.
4. Ditch stackstring entirely. It was complained about by Zach during the review although defended by the author as "stackstring is barely on-stack buffer optimization - it isn't general string and never intended to be so. It isn't in details because it can actually be useful outside library scope." So this would worsen performance a bit as usual SSO are to small for common filenames.
You are going to need some string object, unless the library is strictly for C users <g>, so ditching stackstring does not seem like a solution.
Thanks for reading and any insight is welcome!
The gist is, with all respect to Stroustrup, that the time has been long past when C++ should worry about C-isms, or bend library design to accomodate C programmers. Any C++ programmer who actually wants to use 'freopen' and pass NULL, can manually check their string object for an empty string and pass NULL to 'freopen' is that is the case.
2. Disallow NULL (via assert) for all conversions and require manual checking. Best usage would then probably be to ditch the temporary and do `return _wfFoo(s ? wstackstring(s).c_str() : NULL);`
or with some kind of gsl::not_null would be even better?
int fFOO(gsl::not_null
Alexander Grund wrote:
Hi,
in my work on Boost.Nowide I encountered a valid NULL string and am unsure how to handle it.
Context: Every wrapper functions is basically implemented like:
int fFOO(const char* s){ wstackstring const ws(s); // Converts UTF-8 to wchar-buffer/string return _wfFoo(ws.c_str()); }
Similar functions like `std::wstring widen(string-or-const-char-ptr)` are provided which can be used like `return _wfFoo(widen(s).c_str());` in the example above.
All was fine, because (IIRC) calling e.g. `fopen(NULL)` is not allowed anyway.
However `freopen` DOES allow a NULL for the string. So now I'm left with a couple options and would like some opinions on them:
1. Make (w)stackstring aware of NULL input and if default constructed or with NULL return NULL for c_str().
This. Since (w)stackstring is an internal utility class, we should make it behave in whatever way is most useful for the implementation, and in this case, NULL-in-NULL-out is correct.
participants (6)
-
Alexander Grund
-
Artyom Beilis
-
Edward Diener
-
Frédéric
-
Gavin Lambert
-
Peter Dimov