it-swarm.it

Perché i puntatori non sono consigliati quando si codifica con C ++?

Ho letto da qualche parte che quando si utilizza C++ si consiglia di non utilizzare i puntatori. Perché i puntatori sono una cattiva idea quando si utilizza C++? Per i programmatori C che sono abituati a usare i puntatori, qual è l'alternativa e l'approccio migliori in C++?

45
Joshua Partogi

Penso che significhino che dovresti usare puntatori intelligenti invece di puntatori regolari.

In informatica, un puntatore intelligente è un tipo di dati astratto che simula un puntatore fornendo allo stesso tempo funzionalità aggiuntive, come la garbage collection automatica o il controllo dei limiti. Queste funzionalità aggiuntive hanno lo scopo di ridurre i bug causati dall'uso improprio dei puntatori mantenendo l'efficienza. I puntatori intelligenti in genere tengono traccia degli oggetti a cui puntano ai fini della gestione della memoria.

L'uso improprio dei puntatori è una delle principali fonti di bug: l'allocazione, la deallocazione e il riferimento costanti che devono essere eseguiti da un programma scritto utilizzando i puntatori introducono il rischio che si verifichino perdite di memoria. I puntatori intelligenti tentano di prevenire perdite di memoria rendendo automatica la deallocazione delle risorse: quando il puntatore (o l'ultimo di una serie di puntatori) su un oggetto viene distrutto, ad esempio perché esce dall'ambito, anche l'oggetto appuntito viene distrutto.

In C++ l'enfasi sarebbe sulla garbage collection e sulla prevenzione delle perdite di memoria (solo per citarne due). I puntatori sono una parte fondamentale del linguaggio, quindi non usarli è praticamente impossibile se non nella maggior parte dei programmi.

58
jmq

Dal momento che sono io che ho pubblicato la polemica "non usare f * cking pointers" Sento che dovrei commentare qui.

Prima di tutto, come polemica rappresenta ovviamente un punto di vista estremo. There are usi decisamente legittimi di puntatori (grezzi). Ma io (e molti programmatori professionisti C++) ritengo che questi casi siano estremamente rari. Ma ciò che intendiamo veramente è il seguente:

Primo:

I puntatori non elaborati non devono in alcun caso possedere memoria.

Qui, "propria memoria" significa essenzialmente che ad un certo punto delete è chiamato su quel puntatore (ma è più generale di così). Questa affermazione può essere tranquillamente considerata come assoluta. L'eccezione solo è quando si implementa il proprio puntatore intelligente (o altro strategia di gestione della memoria). E anche lì dovresti normalmente ancora usare un puntatore intelligente a basso livello.

La logica di ciò è abbastanza semplice: i puntatori non elaborati che possiedono la memoria introducono una fonte di errore. E questi errori sono prolifici nel software esistente: perdite di memoria e doppia eliminazione - entrambe conseguenze dirette della proprietà poco chiara delle risorse (ma andando nella direzione opposta).

Questo problema può essere completamente eliminato, praticamente a costo zero, semplicemente usando i puntatori intelligenti anziché i puntatori non elaborati (avvertenza: questo richiede ancora di pensare, naturalmente; puntatori condivisi può portare a cicli e quindi una volta di nuovo a perdite di memoria - ma questo è facilmente evitabile).

Secondo:

La maggior parte degli usi dei puntatori in C++ non sono necessari.

A differenza di altri linguaggi, il C++ ha un supporto molto forte per la semantica di valore e semplicemente non ha bisogno del riferimento indiretto dei puntatori. Ciò non è stato immediatamente realizzato - storicamente, il C++ è stato inventato per facilitare il facile orientamento degli oggetti in C, e si basava fortemente sulla costruzione di grafici di oggetti collegati da puntatori. Ma nel C++ moderno, questo paradigma è raramente la scelta migliore e i moderni idiomi del C++ spesso non hanno bisogno di puntatori . Operano su valori anziché su puntatori.

Sfortunatamente, questo messaggio non si è ancora diffuso in gran parte della comunità di utenti C++. Di conseguenza, la maggior parte del codice C++ scritto è ancora disseminato di puntatori superflui che rendono il codice complesso, lento e difettoso/inaffidabile.

Per qualcuno che conosce il C++ moderno, è chiaro che raramente hai bisogno di puntatori any (intelligenti o non elaborati; tranne quando li usi come iteratori). Il codice risultante è più breve, meno complesso, più leggibile, spesso più efficiente e più affidabile.

97
Konrad Rudolph

Semplicemente perché ci sono astrazioni disponibili per te che nascondono gli aspetti più temperanti dell'uso dei puntatori, come l'accesso alla memoria grezza e la pulizia dopo le allocazioni. Con i puntatori intelligenti, le classi di contenitori e i modelli di progettazione come RAII, viene ridotta la necessità di utilizzare i puntatori non elaborati. Detto questo, come ogni astrazione, dovresti capire come funzionano effettivamente prima di andare oltre.

15
Ed S.

Relativamente semplicemente, la mentalità C è "Hai un problema? Usa un puntatore". Puoi vederlo in stringhe C, puntatori a funzione, puntatori-come-iteratori, puntatore-puntatore, puntatore vuoto- anche nei primi giorni di C++ con puntatori membri.

Ma in C++ puoi usare i valori per molte o tutte queste attività. Hai bisogno di una funzione di astrazione? std::function. È un valore che è una funzione. std::string? È un valore, è una stringa. Puoi vedere approcci simili in tutto il C++. Questo rende l'analisi del codice molto più semplice sia per gli umani che per i compilatori.

11
DeadMG

Uno dei motivi è un'applicazione troppo ampia di puntatori. Possono essere utilizzati per l'iterazione su contenitori, per evitare la copia di oggetti di grandi dimensioni quando si passa alla funzione, la gestione della vita non banale, l'accesso a luoghi casuali in memoria, ecc. E una volta utilizzati per uno scopo, diventano disponibili le loro funzionalità immediatamente indipendentemente sull'intenzione.

La selezione di uno strumento per lo scopo esatto rende il codice più semplice e l'intento più visibili: iteratori per iterazioni, puntatori intelligenti per la gestione della vita, ecc.

10
maxim1000

Oltre ai motivi già elencati, ce n'è uno ovvio: migliori ottimizzazioni. L'analisi di aliasing è troppo complicata in presenza di un'aritmetica del puntatore, mentre i riferimenti suggeriscono un ottimizzatore, quindi un'analisi di aliasing molto più profonda è possibile se si utilizzano solo riferimenti.

3
SK-logic

Oltre al rischio di perdite di memoria dichiarate da @jmquigley, l'aritmetica del puntatore e del puntatore può essere considerata problematica perché i puntatori possono puntare ovunque nella memoria causando "bug difficili da trovare" e "vulnerabilità della sicurezza".

Ecco perché sono stati quasi abbandonati in C # e Java.

2
k3b