Re: A style question on const char* vs. std::string
Zeljko Vrba wrote:
std::map<type_a, const char*> some_map;
type_a is an enum type. The some_map is filled with strings on program
startup; it is supposed to be 1:1 mapping for each enum element.
Okay.
I am aware that this is better done with a static array of
strings or boost::array.
Is it? Why? When I need mapping to a string, I just provide an overload for
to_string(whatever_type), returning either a 'char const*' or
a 'std::string', depending on whether the content is static or needs to be
constructed.
Another person has proposed to use std::map<type_a, std::string>, one of
the arguments being that "it's safer".
In general, unless you have reasons not to, use the most simple thing that
works, in many cases that is a standard container. Since you need to insert
the names into the map manually anyway, you can also go with a manually
written switch statement (or use a regular expression to generate one of
them from the enum definition).
Namely, referencing an unitialized element in the map (some_map[blah])
will insert and return a default-constructed value type.
I'd use map::find() and assert(false) if there is no value found. Otherwise
I would return a noticeable default value but I would never insert things
into that map, in particular since I don't want the overhead of having to
lock in for concurrent accesses.
When the value type is const char*, its default is NULL, and this is
what gets returned to the caller, resulting in a crash as soon as
the value is used. Since the mapping is supposed to be 1:1, and
referencing an uninitialized element is a programmer's error, I
believe that crashing is a GOOD thing and an early indication of
faulty program.
Yes, try to create errors as early as possible and with best possible
diagnostics. Did I mention assert()ing that the value is in the map?
I have in addition claimed that using std::string (in this particular
scenario, NOT in general!) would actually hide errors and push them
deeper in the program logic where they would be harder to discover.
No, it's rather returning a value at all when there is none which serves
to hide errors. Beware, if you 'sprintf( str, "%s", 0)', some
implementations will not produce an error but "(nil)" as content of
'str', so your error might not be caught after all or far away from
where it could have been detected.
Another concern that I expressed is adding a new value to enum, but
forgetting to update the map. It is another problem that using
std::string would hide.
As I said, silently inserting values in the map is the problem. If there
is no value, don't even try to return one. At least throw an exception,
otherwise assert(false).
This another person has said that I do not understand "the fundamental
concepts of the language" (referring to C++), that "I'm welcome to
continue to write C in C++ if I like so", and has referred me to the
following link:
http://www.parashift.com/c++-faq-lite/containers.html#faq-34.1
This is a good link, but doesn't hit the nail in this context, I'd say
that person didn't understand your concerns nor did you understand theirs.
Hmmm, I don't think it's in the C++ FAQ, but the rule is to create errors
as early as something fails. If an enumeration value is out of range,
that is an error and you must either handle this properly or create an
error. Further, you must create the error _right now_ because it signals
a programming error and your program is in an invalid state. Complain
early and loud.
Uli
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]