C++ – Storing a pointer to an argument passed by (non-const) reference

api-designcpointersreference

When designing an interface for passing objects which are meant to be stored for later use and which should not be 'null', I am always a bit uncertain if the argument should be passed by reference or as a pointer.

This is an example of what I mean:

class Foo
{
private:
    Bar* m_bar;

public:
    Foo() : m_bar(nullptr)
    {
    }

    void Register(Bar& bar)
    {
        m_bar = &bar;
        m_bar->Registered();
    }
    // -- OR --
    void Register(Bar* const bar)
    {
        if (bar == nullptr)
        {
            // Error!
        }

        m_bar = bar;
        m_bar->Registered();
    }

    // Some method makes use of the stored pointer later
    void DoSomething()
    {
        if (m_bar == nullptr)
        {
            // Error!
        }

        m_bar->DoOtherThing();
    }
};

My thoughts on this are:

  1. The passed in reference may go out of scope before DoSomething gets called, but that may happen with the pointed to object as well.
  2. Using the pass-by-non-const-reference version gets rid of duplicating the check for null and tells the caller that it is not possible to register 'nothing'.
  3. It would be better to pass a reference in the constructor of Foo as it is required by DoSomething, but sometimes it this is not an option.
  4. It would be better to pass a reference to DoSomething directly, but again, this is not always possible.

So if I need that kind of separate setter/register method, would it be clearer to use a reference or a pointer?

PS I know there is are two very similar questions Storing a pass-by-reference parameter as a pointer – Bad practice? and Reference vs dereference pointers in arguments C++/C, but I think they both are concerned with slightly different problems. The former deals mostly with the (ab)use of const and the latter does not say anything about storing a pointer. There may be another question/answer out there, if so, please just mark this a duplicate then!

Best Answer

Preparing my flame-retardant suit, as I feel some bias must be present in any answer to this question.

First, I would like to note that I work within the embedded world, so RAII and stack allocation are generally the way to go. In almost any circumstance, I see passing something in by reference as a good idea because of the obvious reason: it can't be NULL. But notably, this is because I primarily do stack allocation - so I'm not typically taking something from the heap and stuffing it into a reference when passing it in. This style of programming eliminates common sources of issues for concerns 1, 3, and 4 that you listed.

If I do pass in a pointer, it's for one of two reasons: 1) NULL really is an option (somewhat rare) or 2) I want to signal that my object is taking ownership of the one being passed in. I realize this comes down somewhat to style and domain, but it's a rule of thumb that's helped me make fewer errors and communicate with the programmers on my team about what my code is doing.