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:
- The passed in reference may go out of scope before
DoSomethinggets called, but that may happen with the pointed to object as well. - 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'.
- It would be better to pass a reference in the constructor of
Fooas it is required byDoSomething, but sometimes it this is not an option. - It would be better to pass a reference to
DoSomethingdirectly, 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!
m_baraBarinstead of aBar *and your problem disappears. Also a reference is preferable ifnullptris not a viable argument. – nwp Sep 19 '14 at 17:55Baris an abstract class, this won't work. – Simon Lehmann Sep 19 '14 at 18:35std::unique_ptr<Bar>. Besides accepting anullptrit clearly documents how the interface is to be used. – nwp Sep 19 '14 at 19:06shared_ptrallows this type of use even better than a pointer, because the caller can control how the 'reference' is to be released. – D Drmmr Sep 20 '14 at 20:48shared_ptrto make sure that the object stays valid. If that is too much overhead you need some logic outside ofFoothat makes sure aFoodoes not outlive itsBar. Personally I would try to change the design to not need aRegisterfunction. Could you share whatFooandBaractually are? – nwp Sep 20 '14 at 21:27