2010-07-26 11 views
5

In C++, ff ho una classe che deve contenere un elemento che può essere allocato dinamicamente e utilizzato come puntatore, o meno, così:membri dinamici vs non dinamica classe

class A { 
    type a; 
}; 

o

class A { 
    A(); 
    ~A(); 
    type* a; 
}; 

e nel costruttore:

A::A { 
    a = new type(); 
} 

e distruttore:

A::~A { 
    delete a; 
} 

ci sono vantaggi o svantaggi per entrambi, a parte quello dinamico che richiede più codice? Si comportano in modo diverso (a parte il puntatore che deve essere dereferenziato) o è più lento dell'altro? Quale dovrei usare?

+2

Lavorare su un codice manutenibile corretto e, se necessario, lavorare sulle prestazioni. –

+1

Il tuo secondo 'A' non è sicuro; è necessario definire anche il costruttore di copie e 'operator ='. Mai possedere puntatori del genere, avvolgerli in modo da non dover scrivere * nessuna * funzione membro speciale. – GManNickG

risposta

0

Con il puntatore si ha un maggiore controllo, ma anche più responsabilità. Hai un maggiore controllo nel senso che puoi decidere la vita dell'oggetto con maggiore precisione, mentre senza il puntatore il tempo di vita è essenzialmente uguale alla durata dell'oggetto contenente. Inoltre, con il puntatore il membro potrebbe effettivamente essere un'istanza di una sottoclasse del tipo di puntatore.

delle prestazioni, utilizzando il puntatore non significare più l'utilizzo della memoria, più memoria frammentazione, e dereferenziazione fa prendere tempo. Per tutti, tranne il codice più performante, non vale la pena di preoccuparsi di questo.

0

La differenza principale è che il puntatore può potenzialmente puntare da qualche altra parte.

modificare

risposta di Laurence non è sbagliato, ma è un po 'generale. In particolare, l'allocazione dinamica sarà leggermente più lenta. Anche il dereferenziamento tramite il puntatore sarà leggermente più lento. Ancora una volta, non si tratta di una perdita di velocità, e la flessibilità che acquista potrebbe valerne la pena.

0

La differenza principale è che se non si utilizza un puntatore, la memoria per l'elemento interno sarà assegnato come parte della memoria allocata per l'oggetto contiene. Se si utilizza new, si otterrà memoria in blocchi separati (sembra già che siano stati creati e distrutti correttamente l'oggetto di riferimento in basso)

0

È necessario comprendere le implicazioni del costruttore di copie di default e degli operatori di assegnazione copia quando si utilizzano i puntatori grezzi . Il puntatore raw viene copiato in entrambi i casi. In altre parole, finirai per avere più oggetti (o puntatori grezzi) che puntano alla stessa posizione di memoria. Pertanto, il distruttore scritto come sopra tenterà di eliminare la stessa memoria più volte.

5

ci sono molte differenze:

  1. Le dimensioni di ogni membro deve essere noto quando si sta definendo una classe. Ciò significa che devi includere l'intestazione type e non puoi semplicemente utilizzare una dichiarazione diretta come faresti con un membro puntatore (poiché la dimensione di tutti i puntatori è nota). Ciò ha implicazioni per la clonazione di #include e tempi di compilazione per progetti di grandi dimensioni.

  2. La memoria per l'elemento di dati è parte dell'istanza classe contenitrice, quindi saranno assegnati allo stesso tempo, nello stesso luogo, come tutti gli altri membri della classe (sia alla pila o mucchio). Ciò ha implicazioni per la localizzazione dei dati: avere tutto nello stesso posto potrebbe portare a un migliore utilizzo della cache, ecc. L'allocazione dello stack sarà probabilmente un po 'più veloce dell'allocazione dell'heap. Dichiarare troppe istanze di oggetti enormi potrebbe far saltare il tuo stack più velocemente.

  3. Il tipo di puntatore è più difficile da gestire, poiché non viene automaticamente assegnato o distrutto insieme alla classe, è necessario assicurarsi di farlo da soli. Ciò diventa complicato con più membri del puntatore: se si è nel gruppo new nel costruttore, ea metà del processo c'è un'eccezione, il distruttore non viene chiamato e si verifica una perdita di memoria. È meglio assegnare variabili puntatore a un contenitore "puntatore intelligente" (come std::auto_ptr) immediatamente, in questo modo la pulizia viene gestita automaticamente (e non è necessario preoccuparsi di delete inserirli nel distruttore, salvandoti spesso dalla scrittura uno a tutti). Inoltre, ogni volta che gestisci le risorse manualmente devi preoccuparti dei costruttori di copia e degli operatori di assegnazione.

+0

Aggiungere container smart-pointer-include (stl/boost) al tuo progetto in genere aumenta il tuo tempo di compilazione molto più che includere i tuoi file di intestazione. L'allocazione dello stack, che è considerata a buon mercato, è molto più veloce delle allocazioni dell'heap (che sono considerate costose). Perché dovresti preoccuparti dei costruttori di copia e degli operatori di assegnazione se gestisci le risorse manualmente? Assicurati di mantenere puntatori su di loro invece di copiarli. (dichiara semplicemente copia/assegnazione come privato e non commetterai mai l'errore di sbagliare). – Simon

0

Se la variabile membro dovrebbe vivere oltre la durata dell'oggetto, o se la sua proprietà dovrebbe essere trasferita ad un altro oggetto, quindi l'elemento deve essere dinamicamente (mucchio) allocato utilizzando "nuovo". Se non lo è, allora è spesso la scelta migliore per renderlo un membro diretto della classe al fine di semplificare il codice e ridurre il carico sull'allocatore di memoria. L'allocazione della memoria è costosa.