C'e' una differenza filosofica/subdola tra reference e puntatore.
Iniziamo con il dire che un reference E' un puntatore.
Quello che succede e' che il compilatore aggiunge AUTOMATICAMENTE un “&” (prendi l'indirizzo) ed un “*” (vai a quell'indirizzo)
OGNI VOLTA che deve essere passato un valore via reference OPPURE un parametro di tipo reference viene usato.
Questo fa si che, A PARTE FORZATURE fatte da parte del programmatore, un reference NON POTRA' MAI ESSERE NULLO.
Un “puntatore”, invece, PUO' essere NULLO (a suo tempo rappresentato con lo 0 --zero-- e la macro NULL, ora anche con la keyword “nullptr”). E poiche' il puntatore potrebbe essere nullo, in “teoria” il codice dovrebbe SEMPRE fare i controlli del caso.
Il “pasticcio impasticciato" nasce quando si vuole usare un puntatore come reference, per il motivo di cui sopra (essere NULLO).
In “teoria” usare un reference come puntatore NON E' un problema per la natura stessa di reference: e' un puntatore SICURAMENTE NON NULLO.
MA, ovviamente, SE si converte un puntatore (che potrebbe essere NULLO) in un reference ed il reference in un puntatore, si e' fortunati SE l'applicazione sputa SOLO in un occhio e non in tutti e due :-)
Il pasticcio si impasticcia ulteriormente quando si usa il trucco del puntatore per fare delle conversioni di tipi. Ma questa e' un'altra storia.
Il concetto “std::optional” e' abbastanza recente e cerca di FORZARE il programmatore a RICORDARSI che il puntatore potrebbe essere NULLO e quindi fare i controlli del caso. AIUTA MA NON RISOLVE i problemi di cattiva programmazione.