Gama said:
I'm designing an interface for a shared library, and I would like to
know if there is a standard about how to return an object to the user. I
will use exceptions to report errors, so there are at least four ways to
do it.
More, actually. You still can return by value. And often that is
the preferred method. You can pass a pointer to an object by reference
and you can pass a pointer to an object by pointer.
For example if we have a method named M, that receives a reference to
parameter p and returns object o.
If it "returns object o", why are you trying to return a pointer or
a reference? Doesn't "returns object" mean "by value"?
1 - virtual o& M(p& parameter) throw(Exception1, Exception2...
2 - virtual o* M(p& parameter) throw(Exception1, Exception2...
3 - virtual void M(p& parameter, o& returnVal) throw(Exception1,
Exception2...
4 - virtual void M(p& parameter, o* returnVal) throw(Exception1,
Exception2...
Probably there is no convention about it and is only a mater of taste,
but I would like to know some opinions.
The differences are significant. First of all, you clearly returning
a pointer or a reference to a _non_const_ object. Where is that object
residing? Is it part of the object for which the member function 'M'
is called? Then returning a reference or a pointer is often OK, but
the lifetime of the "returned" object will depend on the lifetime of
the object for which you call 'M'. So, there is a dependency, which
many prefer to avoid.
Second, a pointer can be null, so any time somebody returns a pointer
to me, I need to write code to verify that it's valid. A reference can
never be null, no matter what some of your college buddies say. So,
here is one important difference. Another difference is that it's much
easier to deal with pointers if they are to a dynamically created object.
No, it's not impossible to work with a reference in that case
int &ir = *(new int(42));
delete &ir;
but it's ugly. So, if you're creating an object in free store, return
a pointer. Also, thoroughly document that fact so that the user won't
forget to dispose of the object properly (in the case of returning by
value there is no disposal headache).
Cases 3 and 4 assume that (a) the object exists outside and (b) its type
provides some kind of assignment semantics. In that case, you have more
of a question "what's the preferred way of passing objects into functions"
and not "what's the preferred way of returning objects". So, it's quite
different from the first two.
You could merge the cases 3 and 4 into "pass a pointer to an object by
reference" so that you could change it inside the function to point to
something meaningful. In that case the user doesn't have to create
an object before calling your function and you can return the address of
something allocated dynamically. You cannot have a reference to another
reference, so there is only one more case you didn't mention: pass
a pointer to a pointer:
virtual void M(p& parameter, o** returnValPtr) throw(Exception1, ..
which is not bad, but the same implication applies: _you_ need to check
that I didn't pass a null pointer to you, and when the function returns,
I have to check that the value of 'returnValPtr' is not null before I
can use the object.
Victor