In C ++ Buone ragioni per NON usare la gestione simmetrica della memoria (cioè nuova ed eliminazione)

3

Cerco di imparare C ++ e la programmazione in generale. Attualmente sto studiando open source con l'aiuto di UML. L'apprendimento è il mio hobby e anche quello fantastico.

La mia comprensione dell'allocazione della memoria in C ++ è che dovrebbe essere simmetrico. Una classe è responsabile delle sue risorse. Se la memoria è allocato utilizzando nuovo deve essere restituito utilizzando l'eliminazione nello stesso classe. È come in una biblioteca di cui tu, la classe, sei responsabile i libri che hai preso in prestito e li restituisci, allora hai finito.

Questo, secondo me, ha senso. Rende più la gestione della memoria gestibile per così dire.

Fin qui tutto bene. Il problema è che questo non è il modo in cui funziona nel mondo reale.

Ad esempio in Qt, si crea QtObjects con new e poi si consegna la proprietà dell'oggetto a Qt. In altre parole, crei QtObjects e Qt li distrugge per te. Quindi gestione della memoria asimmetrica. Ovviamente le persone che stanno dietro a Qt devono avere una buona ragione per farlo. Deve essere utile in qualche modo,

Le mie domande sono:

  • Qual è il problema con l'idea di Bjarne Stroustrups su un simmetrico gestione della memoria contenuta in una classe?
  • Cosa guadagni dividendo di nuovo ed elimina così crei un oggetto e distruggerlo in classi diverse come fai in Qt.
  • È comune dividere nuovi ed eliminare e perché in tal caso, in altri progetti che non riguardano Qt?

Grazie per l'aiuto che fa luce su questo mistero!

    
posta Jim G 11.06.2014 - 20:36
fonte

6 risposte

6

Nel C ++ moderno in genere si desidera utilizzare l'idioma Acquisizione risorse è inizializzazione (RAII) . L'idea è che ogni risorsa che si assegna dovrebbe essere racchiusa in una classe, e dovrebbe essere cancellata / chiusa / ripulita dal distruttore della classe. Una risorsa è tutto ciò di cui hai bisogno per de-allocare, chiudere o pulire in altro modo quando hai finito. Molto spesso una risorsa è memoria, ma potrebbe essere altre cose come i file o le connessioni di rete.

In alcuni casi la classe di wrapping può essere complessa, rappresentando una parte della logica del programma. Nella maggior parte dei casi la classe di wrapping può essere molto semplice, esiste solo allo scopo di de-allocare la risorsa nel momento giusto nel modo giusto. Un esempio di questo è un puntatore intelligente .

Non ho guardato Qt da molto tempo. Tuttavia, lasciare che l'utente assegni un oggetto e passare un puntatore non elaborato in una funzione di libreria che successivamente lo desalinga è uno schema piuttosto obsoleto. Se la funzione Qt genera un'eccezione prima che abbia la possibilità di cancellare il tuo oggetto, avrai inevitabilmente una perdita di memoria. L'oggetto deve essere racchiuso in un puntatore intelligente, il cui distruttore lo eliminerà automaticamente, incluso il caso in cui viene lanciata un'eccezione.

    
risposta data 11.06.2014 - 20:49
fonte
1
  • What is the problem with Bjarne Stroustrups idea about a symmetrical memory management contained within a class?

Nella maggior parte dei casi, non vi è alcun problema con la gestione simmetrica della memoria. Questo è anche ciò su cui si basa il principio di RAII .
Esistono tuttavia sempre situazioni in cui la classe che ha assegnato memoria non è l'ultima a cui è necessario fare riferimento. A volte questo può essere risolto passando la proprietà (e quindi la responsabilità per la cancellazione) a un'altra classe. A volte non è nemmeno chiaro chi sarà l'ultimo a fare riferimento a un pezzo di memoria. In questi casi, le tecniche di raccolta dei rifiuti come il conteggio dei riferimenti sono utili.

  • What do you gain by splitting new and delete so you create an object and destroy it in different classes like you do in Qt.

Ottieni ulteriori possibilità di design. Ad esempio, se si dispone di un contenitore polimorfico, la classe che inserisce gli elementi in essa non è tenuta a sopravvivere al contenitore stesso e alle classi che ne leggono. Questo può essere utile nell'implementazione di interfacce grafiche.

  • Is it common to split new and delete and why in such case, in other projects not involving Qt?

Data la popolarità di boost::shared_ptr<> e l'introduzione di std::shared_ptr<> nel recente aggiornamento C ++, ci deve essere qualche richiesta per una gestione della memoria simmetrica. Entrambe le classi implementano la proprietà della memoria condivisa in base al conteggio dei riferimenti.

    
risposta data 11.06.2014 - 22:00
fonte
1

Mi avvicinerei alla direzione opposta: perché la posizione di Bjarne è una buona idea? Quindi possiamo vedere quando cade a pezzi.

La ragione principale della posizione di Bjarne nella gestione della memoria simmetrica è che C ++ può causare perdite di memoria se la proprietà della memoria non viene gestita correttamente. La posizione di Bjanrne si basa sull'idea che la gestione simmetrica della memoria aumenta la probabilità che gli sviluppatori gestiscano correttamente la memoria e minimizzi le perdite.

Fa ciò mantenendo la gestione della memoria fuori dalle interazioni tra le classi. In generale, le chiamate di funzione non notificano esplicitamente i comportamenti di gestione della memoria. Quelli tendono ad essere relegati ai commenti. I commenti possono essere trascurati.

Nel mondo reale, non è sempre conveniente fare la gestione della memoria simmetrica. Ad esempio, qualsiasi dato necessario per gestire correttamente la memoria deve avere una durata di vita pari ai dati stessi (altrimenti non sarebbe valido se fosse necessario). Nel codice della vita reale, gli sviluppatori taglieranno gli angoli per migliorare la leggibilità della loro API.

Lo sviluppo moderno ha visto l'introduzione di shared_ptr. shared_ptr risolve questi problemi inserendo le regole di gestione della memoria direttamente nella definizione della funzione, e lo fa in un modo che è così popolare tra gli sviluppatori, che le persone trovano pochi motivi per eseguire il rollover.

Shared_ptr soddisfa la regola di Bjarne mettendo tutta la gestione della memoria in un unico posto: shared_ptr, e soddisfa i bisogni della vita reale consentendo il passaggio della proprietà della memoria da un luogo all'altro.

    
risposta data 12.06.2014 - 04:14
fonte
0

What is the problem with Bjarne Stroustrups idea about a symmetrical memory management contained within a class?

What do you gain by splitting new and delete so you create an object and destroy it in different classes like you do in Qt.

Quando usi la gestione simmetrica della memoria devi ricordare se hai chiamato l'operatore "cancella" sull'oggetto o meno. Aumenta la complessità della programmazione (che può aumentare la quantità di perdite di memoria) ma ti dà il controllo sul ciclo di vita della variabile. D'altra parte se usi una sorta di garbage collection (ad esempio in Java - puoi creare oggetti ma non gestirne l'eliminazione) diminuisce la complessità ma a volte può causare problemi con le prestazioni.

Is it common to split new and delete and why in such case, in other projects not involving Qt?

Dipende dai progetti. È una questione di prestazioni necessarie per il progetto.

L'idea è la scelta tra minore complessità (in caso di GC) o prestazioni più elevate (in caso di gestione manuale della memoria).

P.S. L'idea alla base della raccolta dei dati inutili e il passaggio del puntatore a qualche oggetto principale sono tutti uguali: incapsulamento dei dettagli di gestione della memoria. Ma GC è molto meglio (non devi controllare se hai passato il puntatore all'oggetto master - è nascosto all'utente, quindi la complessità è inferiore).

    
risposta data 11.06.2014 - 21:17
fonte
0

Ricorda che Qt è in circolazione da molto tempo e precede C ++ 11 da almeno un decennio. Mi piacerebbe vedere che Qt usi approcci più moderni e fare più affidamento su std :: classes e contenitori e simili, ma ciò rappresenterebbe molto lavoro per loro conto e interromperà la compatibilità con la base di codice installata piuttosto ampia.

Potresti considerare CopperSpice come un'alternativa a Qt, che è stata modernizzata.

link

    
risposta data 09.06.2018 - 15:56
fonte
0

Qt utilizza un paradigma diverso per la gestione della memoria (almeno nel caso di% istanze diQObject), che è abbastanza naturale nel suo caso.

Le UI grafiche sono generalmente create come gerarchie di widget (o controlli / viste / finestre in altri toolkit). Quando un widget figlio viene aggiunto a un genitore, è previsto che faccia parte della gerarchia finché a) non viene rimosso esplicitamente da esso (in Qt, puoi semplicemente chiamare delete per farlo), oppure b) l'oggetto genitore è distrutto (ad esempio, una finestra di livello superiore viene chiusa da un utente).

In altre parole, in questo caso i genitori QObjects controllano la durata dei loro figli, e per questo motivo sono responsabili della loro distruzione.

Direi che la gestione simmetrica della memoria è un buon approccio predefinito, ma in questo caso particolare, passare la proprietà a un altro oggetto sembra essere più naturale.

    
risposta data 09.06.2018 - 18:20
fonte

Leggi altre domande sui tag