2009-02-27 10 views
9

È considerato maleducato/cattiva pratica collocare esplicitamente i membri dell'oggetto nello heap (tramite nuovo)? Penso che potresti voler consentire al client di scegliere la regione di memoria per creare un'istanza dell'oggetto. So che potrebbe esserci una situazione in cui i membri dell'heap potrebbero essere accettabili. Se conosci una situazione potresti descriverla per favore?Etichetta C++ sulle variabili membro nell'heap

+0

Cosa intendi con "vuoi consentire al cliente di scegliere"? –

+0

Chiunque stia utilizzando la classe definisce dove viene archiviata l'istanza. I.E .: ClassICreated client_obj = new ClassCreated;/* o */ClassCreated client_obj; – bluehavana

+0

Chiede informazioni su * member variables * e dove vengono messi in memoria. Se impili uno stack-Foo: Foo foo; I membri del puntatore di Foo possono andare nell'heap senza che l'utente se lo aspetti. È possibile consentire all'utente di specificare un allocatore per aggirare questo problema. – tgamblin

risposta

13

Se si dispone di una classe progettata per la semantica della copia e si sta allocando/deallocando un po 'di memoria inutilmente, ho potuto vedere che si tratta di una cattiva pratica. In generale, però, non lo è. Ci sono molte classi che possono fare uso dell'heap storage. Assicurati di non avere perdite di memoria (disassocia le cose nel distruttore, numero di riferimenti, ecc.) E stai bene.

Se si desidera maggiore flessibilità, considerare di consentire all'utente di specificare un Allocator. Spiegherò.

Determinate classi, ad es. std::vector, stringa, mappa, ecc. necessario archivio per le strutture di dati che rappresentano. Non è considerato maleducazione; Quando hai un assegnato automaticamente vector, l'utente deve sapere che un buffer è allocato quando il costruttore vector viene chiamato:

void foo() { 
    // user of vector knows a buffer that can hold at least 10 ints 
    // gets allocated here. 
    std::vector<int> foo(10); 
} 

Allo stesso modo, per std::string, sapete che c'è una interna, heap allocata char*. In genere, l'istanza per l'istanza string è fino all'implementazione STL; spesso vengono conteggiati i riferimenti.

Tuttavia, per quasi tutte le classi STL, gli utenti do possono scegliere dove posizionare le cose, in quanto possono specificare un allocatore. vector è definito come tipo di questo:

template <typename T, typename Alloc = DefaultAllocator<T> > 
class vector { 
    // etc. 
}; 

Internamente, vector utilizza Alloc (che di default è qualunque allocatore predefinito è per T) per allocare il buffer e altre memorie mucchio può avere bisogno. Se gli utenti non piace la strategia di allocazione di default, si possono specificare uno di loro:

vector<int, MyCustomAllocator> foo(10); 

Ora, quando il costruttore assegna, userà un MyCustomAllocator al posto del default. Ecco alcuni details on writing your own STL allocator.

Se si è preoccupati che potrebbe essere "cattive maniere" utilizzare l'heap per un determinato spazio di archiviazione nella propria classe, si potrebbe voler considerare di fornire agli utenti della classe un'opzione come questa in modo che possano specificare come vanno le cose da allocare se la strategia predefinita non soddisfa le loro esigenze.

+0

Ti voterei, ma non ho il rappresentante.Finora questa è un'ottima risposta, grazie. – bluehavana

+0

Questa risposta e la risposta di Matt Davis meritano entrambi di essere accettate. Dal momento che nessun Rep è stato ottenuto dall'accettazione, lascia che siano entrambe ottime risposte. Grazie mille. – bluehavana

0

hmm, non capisco la tua domanda.

Se si dispone di una classe:

class MyOtherClass; 
class MyClass 
{ 
    MyOtherClass* m_pStruct; 
}; 

Quindi, il client di MyClass non hanno una reale possibilità di scelta su come verrà assegnato m_pStruct.

Ma sarà la decisione del cliente su come sarà essere a sua volta assegnata la classe MyClass, sia in pila o sul mucchio:

MyClass* pMyClass = new MyClass; 

o

MyClass myClass; 
1

dove la classe mette la sua i membri sono meno importanti di quanto la gestione di essi sia contenuta all'interno della classe; i clienti e le sottoclassi non dovrebbero preoccuparsi della variabile membro dell'oggetto.

Il modo più semplice per farlo sarebbe quello di farle impilare le variabili. Ma in alcuni casi, ad esempio se la tua classe ha una struttura di dati dinamica come una lista collegata, non ha senso.

Ma se ci si assicura che gli oggetti vengano ripuliti dopo se stessi, dovrebbe andare bene per la maggior parte delle applicazioni.

10

Non considero affatto una cattiva pratica. Ci sono tutti i tipi di motivi per cui potresti voler allocare esplicitamente una variabile membro tramite nuova. Eccone alcuni in cima alla mia testa.

  • Supponiamo che la tua classe abbia un buffer molto grande, ad es. 512 kb o 1 MB. Se questo buffer non è archiviato nell'heap, gli utenti potrebbero potenzialmente superare lo stack space predefinito se creano più variabili locali della classe. In questo caso, avrebbe senso allocare il buffer nel costruttore e memorizzarlo come puntatore.
  • Se si sta facendo qualsiasi tipo di conteggio dei riferimenti, è necessario un puntatore per tenere traccia del numero di oggetti che puntano effettivamente ai dati.
  • Se la variabile membro ha una durata diversa dalla classe, un puntatore è la strada da percorrere. Un perfetto esempio di questo è la valutazione lazy, in cui si paga solo per la creazione del membro se l'utente lo richiede.
  • Sebbene non sia necessariamente un vantaggio diretto per gli utenti, il tempo di compilazione è un altro motivo per utilizzare i puntatori anziché gli oggetti. Se inserisci un oggetto nella tua classe, devi includere il file di intestazione che definisce l'oggetto nel file di intestazione della tua classe. Se si utilizza un puntatore, è possibile inoltrare la dichiarazione della classe e includere solo il file di intestazione che definisce la classe nei file di origine che ne hanno bisogno. Nei progetti di grandi dimensioni, l'utilizzo delle dichiarazioni anticipate può velocizzare drasticamente i tempi di compilazione riducendo la dimensione complessiva delle unità di compilazione.

D'altra parte, se gli utenti creano un sacco di istanze della tua classe per l'uso in pila, sarebbe vantaggioso usare oggetti invece di puntatori per le variabili membro semplicemente perché allocazioni di heap/deallocazioni sono lenti a confronto. In questo caso è più efficiente evitare l'heap, tenendo ovviamente conto del primo punto sopra.

+0

Se potessi accettare due risposte, accetterei questo e quello di tgamblin. Grazie per tutte le varie situazioni, sono tutte abbastanza diverse per darmi una visione ampia e pragmatica dell'ambito e delle soluzioni del problema. – bluehavana

Problemi correlati