The next stop in my ongoing series going into too much detail about what type of reference to use when is bare pointers (see motivation and parts 1 and 2). Even though we now have an abundance of smart pointers to choose from – about which I’ll have more to say in future installments – the bare pointer (i.e. one that is not smart, aka dumb) still has its uses. Really the best way to think of them is as references that can be set to null.
As with references: when you return a bare pointer you’re telling the caller “you can use this as long as I’m around”, but in this case you’re also telling the caller “I might not be giving you anything, check first”. It used to be that you would need to specify in a function’s documentation whether you were transferring ownership by returning a pointer. Today that is no longer the case: if you’re transferring ownership you should be returning a smart pointer, not a bare one. The fact that you’re returning a smart pointer documents that some kind of ownership change is taking place, while the type of smart pointer documents what type of change is going on (more on that in a later installment).
The same thread synchronization concerns that apply to reference return values apply here: if you return a pointer to an object that will be available in multiple threads then that object needs to be internally synchronized and the pointer cannot be invalidated while it is in use. If you can’t guarantee this the you should be using a
shared_ptr to a
const object instead of a bare pointer (see part 2 for more on this, just substitute pointer everywhere you see reference).
The only reason to choose a bare pointer over a reference for a function argument is to allow the user to pass null if desired, making the argument optional. If it doesn’t make sense for an argument to be null then you should be taking a reference instead; that way you don’t need to check the reference for validity in your function body and you don’t mislead the caller into thinking that null is an OK value to pass in. As with reference arguments: be sure to use
const as needed (i.e. most of the time) to express your intentions towards the passed in object.
Following the theme of like a reference but can be null: you should only use a bare pointer as a member variable in situations where you would use a reference but you either need to allow for the referenced object to be missing or you’ll need to change which object is being referenced at some point. The same caveats about object lifetime apply: the object needs to be around as long as the pointer could be referencing it. If you don’t need nullability or mutability then use a reference instead.
Next up: unique_ptr