[sword-devel] C++ design question

Paul Gear sword-devel@crosswire.org
Fri, 21 Jan 2000 22:35:28 +0000


Scott Davis wrote:

> ...
> 2) returning by pointer   CData *getText()
> gets away from the problems of returning by copy, but introduces its own
> problems.  If this is actually CData* SomeClass::getText() and SomeClass
> is simply returning a pointer to internal data that it takes care of, that
> will work well.  But declare it as const CData *getText() so that you can
> modify or delete SomeClass's internal data.  If this is not the case, and
> getText would have to dynamically create the CData object and then return
> it, you are asking for trouble.  Not a problem as long as you **DOCUMENT
> STRONGLY**, but you will need to make sure that the CData objects are
> deleted by the calling code.
>
> 3) using a reference.
> Probably the best way to do it in htis case, if I understand the problem
> correctly.  Create an empty CData object and pass it to the getText()
> method.  getText fills the object and returns it.  Safe. Easy.  No mess.
> Just my 2 cents, of course.
> ...
> On 21 Jan 2000, Torsten Uhlmann wrote:
>
> > ...
> > I have created a class CData which will hold the result of a query to a
> > module, module type, data type and used key, so it can hold qiet some
> > data. I don't know what is the proper way of returning such an
> > object. Possibilities are:
> >
> > CData getText(key) or
> > getText(key, CData&) or
> > CData *getText(key)
> >
> > In the last one the caller has to destroy the CData object itself.
> > I want to do it right this time so I would like you to give me advise!
> >
> > Thanks for your response...

Scott is definitely right about the 'no correct answer' part.  I would agree
with him that returning by copy is most likely not an option.

There are some good and bad points about pointers and references.  Pointers
must have their memory management handled manually.  i.e. 'new' and 'delete'
must be explicitly called.  This is OK, as long as you decide (and document,
as Scott said) who does the creating and destroying.  I think it is usually
easiest to let the client code do all the memory management, and just pass
the pointers in and out of the class.  So in your example, i would use:
    bool getText( key, CData *result )
where the return code indicates success or failure (if appropriate), and the
result is stored in CData.  Another issue with pointers is that they look
uglier in your code (assuming you think 'foo->func()' looks uglier than
'foo.func()' as i do :-).

References look much cleaner in the code, and have the feature that once
assigned, they cannot be changed.  i.e. The following code is illegal:
    Foo &foo;
    Foo bar;
    foo = bar;
To assign 'foo' to point to 'bar', you must do:
    Foo bar;
    const Foo &foo( bar );
Whether this is an advantage or not depends on what you want to do.  If you
need to reassign it, you must use pointers.

Another issue with references is that it is sometimes unclear when their
constructors and (more importantly) destructors get called.  Whether or not
this is an issue probably depends on how significant your constructors and
destructors are.  i.e. Will they screw things up if they are called at the
wrong time?

Overall, i'd suggest using references in preference to pointers, but be aware
of the issues.  And as Scott said, make sure you get your const-ness right!
--
Paul
---------
"He must become greater; i must become less." - John 3:30
http://www.bigfoot.com/~paulgear