My own rule of thumb :
- Use a reference member when you want the life of your object to be dependent on the life of other objects : it’s an explicit way to say that you don’t allow the object to be alive without a valid instance of another class – because of no assignment and the obligation to get the references initialization via the constructor. It’s a good way to design your class without assuming anything about it’s instance being member or not of another class. You only assume that their lives are directly linked to other instances. It allows you to change later how you use your class instance (with new, as a local instance, as a class member, generated by a memory pool in a manager, etc.)
- Use pointer in other cases : When you want the member to be changed later, use a pointer or a const pointer to be sure to only read the pointed instance. If that type is supposed to be copyable, you cannot use references anyway. Sometimes you also need to initialize the member after a special function call ( init() for example) and then you simply have no choice but to use a pointer. BUT : use asserts in all your member function to quickly detect wrong pointer state!
- In cases where you want the object lifetime to be dependent on an external object’s lifetime, and you also need that type to be copyable, then use pointer members but reference argument in constructor That way you are indicating on construction that the lifetime of this object depends on the argument’s lifetime BUT the implementation use pointers to still be copyable. As long as these members are only changed by copy, and your type don’t have a default constructor, the type should fullfil both goals.