La risposta corretta è:
C. None of the above.
Opzione A:
void fill_array(Array<Type>* array_to_fill);
Questo è più idiomatico per il codice pre-C ++ 11 in cui i puntatori intelligenti erano fastidiosi a causa della mancanza di semantica del movimento e continua a essere il più sicuro delle due opzioni.
Il tasto qui è che la funzione non "possiede" la memoria: esegue un compito e un solo compito. Riempie semplicemente la matrice. La proprietà va oltre lo scopo di ciò che fa ed è per lo più sicura.
Opzione B:
Array<Type>* filled_array();
Questo crea un oggetto all'interno della funzione. Ci sono generalmente due modi per farlo:
- Restituisce un puntatore a un oggetto locale (stack). Questo puntatore non sarà valido a lungo e interromperà qualcosa (UB).
- Restituisce un puntatore a un oggetto (heap) assegnato dinamicamente. Chi possiede l'oggetto? Dove e quando viene liberata la sua memoria? In alcune architetture questo può porre ulteriori problemi. Ad esempio, la piattaforma Windows non consente la liberazione della memoria allocata in un modulo in un'altra (cioè non può allocare nella DLL 1 e libera nella DLL 2).
Opzione C:
std::unique_ptr<Array<Type>> filled_array();
Questo è il modo assolutamente corretto, efficiente, garantito per lavorare.
La memoria è di proprietà del puntatore intelligente e verrà liberata quando il puntatore esce dal campo di applicazione (RAII) e non ha altri puntatori a cui consegnarlo.
All'interno della funzione, ci sarà un puntatore intelligente assegnato a una nuova istanza di array. Il puntatore intelligente possiede quel puntatore di matrice.
La funzione richiama quindi il comportamento attraverso quel puntatore, aggiungendo dati.
Quando la funzione è terminata, restituisce il puntatore intelligente. Poiché il puntatore intelligente esce dall'ambito, si distrugge. Tuttavia, sposta il puntatore che contiene in una nuova istanza nel percorso di chiamata. (Nota: il compilatore potrebbe essere in grado di costruire il puntatore intelligente sul posto nella posizione di chiamata.Indipendentemente, i puntatori intelligenti sono estremamente leggeri e la differenza è minima).
Ora hai un puntatore intelligente nella posizione di chiamata che possiede l'array a cui punta, e quell'array verrà liberato in base alle regole RAII standard. Non ci sono puntatori penzolanti, nessuna perdita di memoria, solo il codice che fa esattamente quello che sembra.