Re: Please help with testing & improving a StringValue class
* Greg Herlihy:
On 9/9/07 12:59 AM, in article firstname.lastname@example.org, "Alf P.
Steinbach" <email@example.com> wrote:
An 01 version of StringValue is now available at
* A license reference (Boost license) is included in every file,
resulting from comments by Roland Pibinger (thanks).
* operator==, operator< added,
resulting from comments by Barry <firstname.lastname@example.org> (thanks).
* Implicit conversion to 'char const*' /removed/, because
* StringValue is now a subclass of a new class StringValueOrNull,
which supports passing null-values around. A StringValue is
therefore implicitly convertible to StringValueOrNull. A
StringValueOrNull value can only be explicitly converted to pure
StringValue, then with checking of nullvalue & possible exception.
* Support for << and >> stream i/o added (because of removal of
implicit conversion to 'char const*').
Comments, ideas, criticism etc. welcome!
Overall, the StringValue class looks very well-designed and implemented.
I do have two small criticisms. First, the StringValue and SharedArray
swap() routines should not be declared in the std:: namespace. As the
comment points out, declaring these swap() routines in the std namespace is
a no-no. Besides, the std namespace is not the optimal place to declare a
swap() routine for a user-defined type - because only those routines in the
std namespace are likely to find it.
A better place to declare a user-defined swap() routine (and where the
Standard actually expects to find it) would be in the same namespace as the
type being swapped (in this case, the "alfs" namespace). Declaring the
swap() routine in the alfs namespace would mean that all routines - not just
those in the std namespace - should be able find it (courtesy of
argument-dependent lookup (ADL)).
Thanks, I'll try that!
Or at least, think about it.
My original thinking was that client code that does
std::swap( a, b );
should just work -- efficiently. But that thinking was not deep
enough. Because with StringValue, assignment, which is probably what
that will result in without overloading that function, is constant time
and with no dynamic allocation, i.e. very efficient anyway.
But it's a shame that std::swap doesn't automatically adjust to classes
with swap member function defined (would an implementation that did
that, be conforming?).
And ditto for std::sort.
Second, I don't see how the concept of "null" is compatible with a
StringValue class (with the emphasis on "value"). In other words, a
StringValue object should have a value (even if it's just an empty string).
The last thing that most C++ programmers want from a utility class is a
"special" valued object of that class that has to be treated differently
than all of the others. And if the program needs to distinguish a null
pointer from an empty string, then it should do so before instantiating a
So my suggestion is that a StringValue object initialized with a null
pointer constant should either throw an exception (probably not warranted)
It does (and did).
or treat the null pointer as an empty string (probably the safer, more
No, that's what the StringValueOrNull class is for: with pure
StringValue I think it's better to catch that as an error or failure (it
also asserts). StringValueOrNull is not meant as a full-featured class.
It's just available as a "compatible" carrier class for the cases
where you need to distinguish null-values, such as from a database lookup.
Or perhaps to cater to the requirements of old C code.
And I finally got the SFINAE / boost::disable_if stuff to work, so now
these two classes, StringValueOrNull and StringValue, are siblings, with
implicit conversion to StringValueOrNull, and only explicit conversion
the other way, then with checking of nullvalue and possible exception
(both conversions constant time no dynamic allocation).
After all, the Standard Library's own string class,
std::string, has no concept of a "null" string - and I have never known
anyone to complain about its absence.
Oh, they do... :-)
Except the "solution" is commonly to use C strings and pointers (ugh).
And one funny solution in one project, in Java, encoding the null value
as a special UUID string value (no fuss with transferring over Corba).
Cheers, and thanks,