Bob Hairgrove wrote:
On Wed, 18 Aug 2004 14:28:53 GMT, Thomas Matthews
<Th****************************@sbcglobal.net> wrote:
[snip]
I would choose to return a _copy_ of the string, not
a reference to the string. A copy allows the string
to be stored elsewhere or computed on-the-fly.
Well, only if you are paranoid about clients grabbing the address of
the string and doing unmentionable things to it (even if it is a const
&) ...
Passing by reference means that the string variable must always
exist.
How could the variable "not exist" if you have a string member? It
might be empty, but it does exist. I can only see a problem if you
have a pointer to a string as member, or perhaps a char *, and try to
dereference it when it is null.
This has bitten me on several occasions. :-(
How?
Let us take an example from the realm of databases.
Let us have a string field which is a column of
strings in a table.
Now let us have a table of the form:
[integer, string]
Such that there is a 1:1 relationship between the
integer and the string. No duplicate strings or
integers are allowed.
I have a class already called Publisher. It is
a string representing a Publisher's name. Here
is the simple class:
class Publisher /* 1 */
{
public:
string get_name(void) const;
private:
string name;
};
I now want to convert the Publisher class to
be a proxy or look-up field. The publisher
class will change from having a string to
having an integer. The get_name() method
will now use the integer as an index into
a table and retrive the string. The Publisher
class becomes:
class Publisher /* 2 */
{
public:
string get_name(void) const;
private:
int record_index;
};
I have changed the _implementation_ but kept
the interface the same. None of the clients
of this class need to be retested and (in
theory[1]) not recompiled.
Had I chosen to to have the get_name() method
to return a "const string&" then I would have
to have a duplicate or resident string
variable[2] because the "reference" notation means
that the variable must exist. This cause more
code and data space:
class Publisher /* 3 */
{
public:
string get_name(void) const;
private:
int record_index;
string name;
};
An even worse problem is that the "get_name()"
method now modifies the "name" member. So it
isn't "const" anymore; but all the clients
expect it to be. Hmmm, now we get ugly.
Enter now "mutable":
class Publisher /* 4 */
{
public:
string get_name(void) const;
private:
int record_index;
mutable string name;
};
The "mutable" modifier now allows a the constant
method "name" to modify the variable. All this
work, simply to statisfy the requirement of using
a reference and because the notion that using
references is more efficient and leads to cleaner,
more readable code. Malarky! Phooey!.
The burning sensation comes from having to:
1. Maintain a mirror[2] or duplicate data member.
{Don't forget that your new design has to
account for determining when the data member
needs to be refreshed or is invalid.}
2. Apply the "mutable" modifier to constant functions.
This application takes away the primary reason
for having private data members in the first place.
----
[1] I said "in theory" because in most systems,
source files are recompiled when their header
files are changed. The above change did not
change the interface so all clients did not
need to be recompiled. {Similar issue with
adding comments}.
[2] In many instances, data fields are mirrored to
speed up access times. The datum is only fetched
from the table once. Additional accesses return
the mirrored value, thus eliminating extra work of
fetching from table. But if the table changes
without knowledge, the mirror concept causes more
problems (using old and probably invalid data).
--
Thomas Matthews
C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq:
http://www.parashift.com/c++-faq-lite
C Faq:
http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book