Return pointers or references?

Discussion in 'C++' started by Gama Franco, Aug 19, 2004.

  1. Gama Franco

    Gama Franco Guest

    Hi,

    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.

    For example if we have a method named M, that receives a reference to
    parameter p and returns object o.

    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.

    Best regards,
    Gama Franco
    Gama Franco, Aug 19, 2004
    #1
    1. Advertising

  2. Gama Franco wrote:
    >
    > 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.
    >
    > For example if we have a method named M,
    > that receives a reference to parameter p and returns object o.
    >
    > 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 matter of taste,
    > but I would like to know some opinions.


    None of the above.
    Use

    virtual o M(const p& parameter) const;

    instead. Pass by *const* reference and return by value.
    E. Robert Tisdale, Aug 19, 2004
    #2
    1. Advertising

  3. Gama Franco

    Phlip Guest

    Gama Franco wrote:

    > 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.
    >
    > For example if we have a method named M, that receives a reference to
    > parameter p and returns object o.
    >
    > 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.


    Smart pointers?

    --
    Phlip
    http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    Phlip, Aug 19, 2004
    #3
  4. Gama Franco wrote:
    > 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
    Victor Bazarov, Aug 19, 2004
    #4
  5. Gama Franco

    Gama Franco Guest

    E. Robert Tisdale wrote:
    > Gama Franco wrote:
    >
    >>
    >> 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.
    >>
    >> For example if we have a method named M, that receives a reference to
    >> parameter p and returns object o.
    >>
    >> 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 matter of
    >> taste, but I would like to know some opinions.

    >
    >
    > None of the above.
    > Use
    >
    > virtual o M(const p& parameter) const;
    >
    > instead. Pass by *const* reference and return by value.

    Hi,

    I forgot to mention something very important. One of the requisites is
    efficiency. I mean, the API should run as fast as possible (it deals
    with scientific data aquisition).

    That is the reason why I only placed the return value as a reference or
    a pointer.

    Thanks in advance,
    Gama Franco
    Gama Franco, Aug 20, 2004
    #5
  6. "Gama Franco" <> wrote...
    > [..]
    > I forgot to mention something very important. One of the requisites is
    > efficiency. I mean, the API should run as fast as possible (it deals
    > with scientific data aquisition).
    >
    > That is the reason why I only placed the return value as a reference or
    > a pointer.


    You didn't mention how you'd be using the returned value or how you'd
    be calling your functions.

    V
    Victor Bazarov, Aug 20, 2004
    #6
  7. > >> 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.
    > >>
    > >> For example if we have a method named M, that receives a reference to
    > >> parameter p and returns object o.
    > >>
    > >> 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 matter of
    > >> taste, but I would like to know some opinions.

    > >
    > >
    > > None of the above.
    > > Use
    > >
    > > virtual o M(const p& parameter) const;
    > >
    > > instead. Pass by *const* reference and return by value.

    > Hi,
    >
    > I forgot to mention something very important. One of the requisites is
    > efficiency. I mean, the API should run as fast as possible (it deals
    > with scientific data aquisition).


    As mentioned virtual o M(...) is the most elegant solution. Often the
    implemention is that the caller allocates the memory for o and M initializes
    it with its return statement, which often defaults to a simple copy
    operation. If you want to get rid of the construction, copying and
    desctruction of the object for each call, you hae to use method 3 or 4. They
    are equal in terms of efficiency. Whether you use pointer or reference does
    not matter in terms of effiency. I prefer using references to emphasize,
    that it is not an array.
    Your methods 1 and 2 have the usual problems related to allocation and
    deallocation:
    - An often made mistake is to return a local object, which goes out of scope
    when the function terminates.
    - It is not clear who is the owner of the objects returned. If they are
    owned by a vector, then the caller should not clean them up. Otherwise it
    might be the task of the caller to clean them up. Or there might be some
    deallocation function in the library...
    Usually I use method 1 and 2 only when the objects are owned by some list or
    vector, where method 3 and 4 are less efficient.

    Niels Dybdahl
    Niels Dybdahl, Aug 20, 2004
    #7
  8. >> 3 - virtual void M(p& parameter, o& returnVal) throw(Exception1,
    >> Exception2...


    Is it fair to say that, following your reasoning, this is generally the
    best option of the four? Maybe it's more a matter of personal coding
    style than of following accepted standards, but :

    1.The returnVal is completely 'managed' by the client. So :
    - There's no danger of a member function lifting an object outside
    it's scope (as in option 1).
    - There's no need documenting that the allocated object should be freed
    by the client (as in option 2).
    2.returnVal doesn't have to be checked for the null value
    (as in option 2 + 4).
    3.Use of pointers is avoided, which is always good for readability.



    Bart
    Bart Blommerde, Aug 20, 2004
    #8
  9. Bart Blommerde wrote:
    >>> 3 - virtual void M(p& parameter, o& returnVal) throw(Exception1,
    >>> Exception2...

    >
    >
    > Is it fair to say that, following your reasoning, this is generally the
    > best option of the four? Maybe it's more a matter of personal coding
    > style than of following accepted standards, but :
    >
    > 1.The returnVal is completely 'managed' by the client. So :
    > - There's no danger of a member function lifting an object outside
    > it's scope (as in option 1).
    > - There's no need documenting that the allocated object should be freed
    > by the client (as in option 2).
    > 2.returnVal doesn't have to be checked for the null value
    > (as in option 2 + 4).
    > 3.Use of pointers is avoided, which is always good for readability.


    Out of four presented, yes, probably. Out of all available, questionable.
    I'd still return by value and let the compiler optimise the hell out of
    it all. It's just semantically clearer. When you write

    SomeClass someObject(blah); // define+initialise
    ...
    someOtherObject.M(someParameter, someObject);

    (which is what you're expected to do in the case 3) it is unclear for the
    reader what's happening. For all we know, M is a void member (that's true
    according to the case 3 declaration) that takes 2 arguments (that's also
    true) and does something to the object 'someOtherObject', and not to its
    second argument.

    V
    Victor Bazarov, Aug 20, 2004
    #9
  10. Gama Franco

    Daniel T. Guest

    In article <>,
    Gama Franco <> wrote:

    > E. Robert Tisdale wrote:
    > > Gama Franco wrote:
    > >
    > >>
    > >> 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.
    > >>
    > >> For example if we have a method named M, that receives a reference to
    > >> parameter p and returns object o.
    > >>
    > >> 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 matter of
    > >> taste, but I would like to know some opinions.

    > >
    > >
    > > None of the above.
    > > Use
    > >
    > > virtual o M(const p& parameter) const;
    > >
    > > instead. Pass by *const* reference and return by value.

    > Hi,
    >
    > I forgot to mention something very important. One of the requisites is
    > efficiency. I mean, the API should run as fast as possible (it deals
    > with scientific data aquisition).
    >
    > That is the reason why I only placed the return value as a reference or
    > a pointer.


    Yet you are making the function virtual? Try returning the object by
    const value first, if profiling shows this is actually a problem (highly
    unlikely IMO) then change it to const reference. No other code will need
    to change in this case.
    Daniel T., Aug 20, 2004
    #10
  11. Daniel T. wrote:
    > [...] Try returning the object by
    > const value first, [...]


    Top-level const qualifiers are meaningless in most situations. And
    I mean

    const int foo();
    void foo(const int);

    V
    Victor Bazarov, Aug 20, 2004
    #11
  12. Niels Dybdahl wrote:

    >>>Use
    >>>
    >>> virtual o M(const p& parameter) const;
    >>>
    >>>instead. Pass by *const* reference and return by value.


    >>I forgot to mention something very important.
    >>One of the requisites is efficiency.
    >>I mean, the API should run as fast as possible
    >>(it deals with scientific data aquisition).

    >
    > As mentioned virtual o M(...) is the most elegant solution.
    > Often the implemention is that the caller allocates the memory for o
    > and M initializes it with its return statement,
    > which often defaults to a simple copy operation.


    No.
    A good optimizing C++ compiler should implement
    the Named Return Value Optimization (NRVO).
    When a function returns the value of a local variable
    the optimizing compiler interprets the local variable
    as a reference to the return value and initializes it directly --
    *no* copy is required!
    Return by value costs no more than any of the other options
    that Gama Franco listed.

    If your compiler does not implement the NRVO,
    you must not be concerned about efficiency or performance
    or you should be shopping for a better optimizing C++ compiler.

    > If you want to get rid of the construction, copying and
    > destruction of the object for each call,
    > you [must] use method 3 or 4. They are equal in terms of efficiency.
    > Whether you use pointer or reference does not matter in terms of effiency.
    > I prefer using references to emphasize, that it is not an array.


    This probably isn't a good idea.

    In-place operations (functions that modify objects)
    should be of the form:

    o& o::M(const p& parameter);

    and return a reference to the object.
    E. Robert Tisdale, Aug 20, 2004
    #12
  13. Gama Franco

    Gama Franco Guest

    E. Robert Tisdale wrote:
    > Niels Dybdahl wrote:
    >
    >>>> Use
    >>>>
    >>>> virtual o M(const p& parameter) const;
    >>>>
    >>>> instead. Pass by *const* reference and return by value.

    >
    >
    >>> I forgot to mention something very important. One of the requisites
    >>> is efficiency. I mean, the API should run as fast as possible (it
    >>> deals with scientific data aquisition).

    >>
    >>
    >> As mentioned virtual o M(...) is the most elegant solution. Often the
    >> implemention is that the caller allocates the memory for o and M
    >> initializes it with its return statement, which often defaults to a
    >> simple copy operation.

    >
    >
    > No.
    > A good optimizing C++ compiler should implement
    > the Named Return Value Optimization (NRVO).
    > When a function returns the value of a local variable
    > the optimizing compiler interprets the local variable
    > as a reference to the return value and initializes it directly --
    > *no* copy is required!
    > Return by value costs no more than any of the other options
    > that Gama Franco listed.
    >
    > If your compiler does not implement the NRVO,
    > you must not be concerned about efficiency or performance
    > or you should be shopping for a better optimizing C++ compiler.
    >
    >> If you want to get rid of the construction, copying and
    >> destruction of the object for each call, you [must] use method 3 or
    >> 4. They are equal in terms of efficiency. Whether you use pointer or
    >> reference does not matter in terms of effiency. I prefer using
    >> references to emphasize, that it is not an array.

    >
    >
    > This probably isn't a good idea.
    >
    > In-place operations (functions that modify objects)
    > should be of the form:
    >
    > o& o::M(const p& parameter);
    >
    > and return a reference to the object.

    Hi,

    I do I know if my compiler does that kind of optimization?
    The code will compile in a great number of versions of g++, and probably
    also in the default compiler of Solaris.
    The program will be used for data aquisition, dealing with data in the
    order of hundreds of megabytes per second. Since we are dealing with the
    refractoring of an existing API, I really would like to make a
    consistent choice without affecting the efficiency of the existing code.
    If most of the compilers use that kind of optimization, probably return
    by value may be the best choice, since the object will get destroyed
    when the variable gets out of scope.

    Best regards,
    Gama Franco
    Gama Franco, Aug 20, 2004
    #13
  14. Gama Franco wrote:

    > I do I know if my compiler does that kind of optimization?
    > The code will compile in a great number of versions of g++,


    My compiler:

    > g++ --version

    g++ (GCC) 3.3.3 20040412 (Red Hat Linux 3.3.3-7)

    does it.

    > and probably also in the default compiler of Solaris.


    Later versions of the Solaris C++ compiler do it too.

    > The program will be used for data aquisition, dealing with data in the
    > order of hundreds of megabytes per second. Since we are dealing with the
    > refractoring of an existing API, I really would like to make a
    > consistent choice without affecting the efficiency of the existing code.
    > If most of the compilers use that kind of optimization,
    > probably return by value may be the best choice,


    It *is* the best choice.
    Most modern C++ compilers support the NRVO
    but what matters is that there is at least one
    good optimizing C++ compiler for each target platform.
    You can do your development with whatever compiler is most convenient
    and then recompile with your best optimizing C++ compiler
    just before you distribute the production release.

    > since the object will get destroyed when the variable gets out of scope.
    E. Robert Tisdale, Aug 20, 2004
    #14
  15. Gama Franco

    Daniel T. Guest

    Victor Bazarov <> wrote:

    > Daniel T. wrote:
    > > [...] Try returning the object by
    > > const value first, [...]

    >
    > Top-level const qualifiers are meaningless in most situations. And
    > I mean
    >
    > const int foo();


    When it comes to basic types like 'int' I agree, but not with user
    defined types. For example if we have:

    value foo();

    Then clients can do:

    value myValue = foo().modify();

    Then changing to 'const value&' will break the program. Better is to
    return 'const value' so that clients can't modify the temporary (making
    user defined types more like basic types) thus allowing us to change to
    a 'const value&' without having to modify any client code.
    Daniel T., Aug 21, 2004
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roger Leigh
    Replies:
    8
    Views:
    436
    Karl Heinz Buchegger
    Nov 17, 2003
  2. Replies:
    3
    Views:
    448
    Victor Bazarov
    Nov 10, 2004
  3. DanielEKFA
    Replies:
    8
    Views:
    606
    DanielEKFA
    May 16, 2005
  4. Greenhorn
    Replies:
    15
    Views:
    812
    Keith Thompson
    Mar 6, 2005
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    672
Loading...

Share This Page