Domanda

Ho scritto un semplice, lavorando gioco tetris con ogni blocco come un esempio di una classe di singleblock.

class SingleBlock
{
    public:
    SingleBlock(int, int);
    ~SingleBlock();

    int x;
    int y;
    SingleBlock *next;
};

class MultiBlock
{
    public:
    MultiBlock(int, int);

    SingleBlock *c, *d, *e, *f;
};

SingleBlock::SingleBlock(int a, int b)
{
    x = a;
    y = b;
}

SingleBlock::~SingleBlock()
{
    x = 222;
}

MultiBlock::MultiBlock(int a, int b)
{
    c = new SingleBlock (a,b);
    d = c->next = new SingleBlock (a+10,b);
    e = d->next = new SingleBlock (a+20,b);
    f = e->next = new SingleBlock (a+30,b);
}

Ho una funzione che esegue la scansione di una linea completa, e attraversa la lista concatenata di blocchi eliminando quelli rilevanti e riassegnazione dei -.> Puntatori successivi

SingleBlock *deleteBlock;
SingleBlock *tempBlock;

tempBlock = deleteBlock->next;
delete deleteBlock;

Il gioco funziona, i blocchi vengono cancellati in modo corretto e tutto funziona come dovrebbe. Tuttavia su ispezione posso comunque accedere bit casuali di dati cancellati.

Se io printf ciascuno dei singleblocks cancellati "x" valori dopo la loro cancellazione, alcuni di loro ritornano spazzatura casuale (che conferma la cancellazione) e alcuni di loro ritorno 222, dicendomi anche se il distruttore è stato chiamato i dati non erano in realtà cancellato dal mucchio. Molti studi identici mostrano che è sempre gli stessi blocchi specifici che non vengono eliminati in modo corretto.

I risultati:

Existing Blocks:
Block: 00E927A8
Block: 00E94290
Block: 00E942B0
Block: 00E942D0
Block: 00E942F0
Block: 00E94500
Block: 00E94520
Block: 00E94540
Block: 00E94560
Block: 00E945B0
Block: 00E945D0
Block: 00E945F0
Block: 00E94610
Block: 00E94660
Block: 00E94680
Block: 00E946A0

Deleting Blocks:
Deleting ... 00E942B0, X = 15288000
Deleting ... 00E942D0, X = 15286960
Deleting ... 00E94520, X = 15286992
Deleting ... 00E94540, X = 15270296
Deleting ... 00E94560, X = 222
Deleting ... 00E945D0, X = 15270296
Deleting ... 00E945F0, X = 222
Deleting ... 00E94610, X = 222
Deleting ... 00E94660, X = 15270296
Deleting ... 00E94680, X = 222

è in grado di accedere ai dati da oltre la tomba previsto?

Scusate se questo è un po 'lungo senza fiato.

È stato utile?

Soluzione

  

è in grado di accedere ai dati da oltre la tomba previsto?

Questo è noto come comportamento indefinito. Non stupitevi se vi offre una lattina di birra sia.

Altri suggerimenti

  

è in grado di accedere ai dati da oltre la tomba previsto?

Nella maggior parte dei casi, sì. Chiamando eliminare non azzerare la memoria.

Si noti che il comportamento non è definito. Utilizzando alcuni compilatori, la memoria può essere azzerata. Quando si chiama elimina, quello che succede è che la memoria viene contrassegnato come disponibile, così la prossima volta che qualcuno fa nuovo , possono essere utilizzati nella memoria.

Se ci pensate, è logico - quando si dice al compilatore che non siete più interessati alla memoria (con Elimina ), perché dovrebbe l'ora del computer spesa per l'azzeramento esso

E 'quello che C ++ chiama comportamento non definito - potrebbe essere in grado di accedere ai dati, potrebbe non. In ogni caso, è la cosa sbagliata da fare.

Elimina non elimina qualsiasi cosa - segna proprio la memoria, come "essere libero per il riutilizzo". Fino a qualche altre riserve di chiamata allocazione e riempie lo spazio che avrà i vecchi dati. Tuttavia, basandosi su che è un grande no-no, in fondo se si elimina qualcosa non pensarci più.

Una delle pratiche in questo senso che si incontra spesso nelle biblioteche è una funzione di eliminazione:

template< class T > void Delete( T*& pointer )
{
    delete pointer;
    pointer = NULL;
}

Questo ci impedisce di accedere accidentalmente memoria non valida.

Si noti che è perfettamente bene di chiamare delete NULL;.

memoria heap è come un mazzo di lavagne. Immaginate di essere un insegnante. Mentre si sta insegnando la classe, lavagna appartiene a voi, e si può fare quello che vuoi fare con esso. È possibile scarabocchiare su di esso e sovrascrivere cose come si desidera.

Quando la classe è finita e si stanno per lasciare la stanza, non esiste una politica che richiede di cancellare la lavagna - è sufficiente consegnare la lavagna fuori al successivo insegnante che sarà generalmente in grado di vedere quello che hai scritto verso il basso.

Il sistema non cancella la memoria quando si rilascia tramite delete(). I contenuti sono quindi ancora accessibili finché viene assegnata la memoria per il riutilizzo e sovrascritto.

eliminare dealloca la memoria, ma non modificarlo o azzerare fuori. Ancora non si deve accedere alla memoria deallocato.

Dopo l'eliminazione di un oggetto non è definito che cosa accadrà ai contenuti della memoria che occupava. Vuol dire che che la memoria è libero di essere riutilizzato, ma l'implementazione non deve sovrascrivere i dati che vi era in origine e non deve riutilizzare immediatamente la memoria.

Non si deve accedere alla memoria dopo che l'oggetto è andato ma non dovrebbe essere surpising che alcuni dati rimane in tatto là.

Non sarà zero / cambio memorie appena ancora ... ma ad un certo punto, il tappeto sta per essere tirato da sotto i piedi.

No, non è certamente prevedibile: dipende da come memoria veloce allocazione / deallocazione è agitato

.

Sì, ci si può aspettare, a volte. Mentre lo spazio riserve new per i dati, delete invalida semplicemente un puntatore creata con new, che consente ai dati di essere scritti nelle posizioni precedentemente riservate; non necessariamente eliminare i dati. Tuttavia, non si dovrebbe fare affidamento su quel comportamento, perché i dati a quelle posizioni potrebbero cambiare in qualsiasi momento, causando il programma a comportarsi male. Questo è il motivo per cui dopo aver utilizzato delete su un puntatore (o delete[] su un array allocato con new[]), è necessario assegnare NULL ad esso in modo che non si può manomettere un puntatore non valido, supponendo che non vi allocare memoria utilizzando new o new[] prima di utilizzare ancora una volta che il puntatore.

E 'porterà ad un comportamento indefinito e cancellare la memoria dealloca, non reinizializzare con zero.

Se si vuole rendere zero fuori poi fare:

SingleBlock::~SingleBlock()

{    x = y = 0 ; }

Anche se è possibile che il tempo di esecuzione non riporta questo errore, utilizzando una corretta esecuzione di controllo degli errori, come Valgrind avviserà l'uso della memoria dopo che è stato liberato.

I raccomandare che se si scrive codice con new / delete e prime puntatori (piuttosto che std::make_shared() e simili), che potrà esercitare i test di unità sotto Valgrind ad almeno avere la possibilità di avvistare tali errori.

Bene, mi sono chiesto su questo per un po 'così, e ho cercato di eseguire alcuni test per capire meglio cosa sta succedendo sotto il cofano. La risposta standard è che dopo aver chiamato Elimina si dovrebbe non aspettatevi nulla di buono l'accesso a quel punto la memoria. Tuttavia, questo non sembra abbastanza per me. Che cosa sta realmente accadendo al momento della chiamata Elimina (PTR) ? Ecco quello che ho trovato. Sto usando g ++ su Ubuntu 16.04, quindi questo può giocare un ruolo nei risultati.

Quello che ho previsto quando si utilizzano l'operatore delete era che la memoria liberata sarebbe stato consegnato al sistema per l'utilizzo in altri processi. Lasciatemi dire questo non accade in una delle circostanze che ho provato.

Memoria rilasciato con eliminare sembrano ancora da assegnare al programma in primo luogo allocato con nuovo . Ho provato, e non v'è alcuna riduzione di utilizzo della memoria dopo aver chiamato Elimina . Ho avuto un software che allcated intorno 30MB di liste attraverso nuovi le chiamate, e poi rilasciato con Elimina / chiamate successive. Quello che è successo è che, guardando il monitor del sistema mentre il programma è in esecuzione, anche un lungo sonno, dopo le Elimina le chiamate, il consumo di memoria il mio programma era lo stesso. Nessuna diminuzione! Ciò significa che Elimina non rilascia la memoria al sistema.

In realtà, sembra che la memoria allocata da un programma è la sua per sempre! Tuttavia, il punto è che, se deallocato, memoria può essere riutilizzato dallo stesso programma senza dover allocare più. Ho cercato di allocare 15 MB, liberandoli, e ripartendo poi un altro 15 MB di dati dopo, e il programma non utilizzato 30 MB. monitor di sistema sempre ha mostrato in giro 15MB. Quello che ho fatto, rispetto al test precedente, era solo per modificare l'ordine in cui le cose successe: la metà di assegnazione, la metà deallocazione, altra metà di allocazione.

Quindi, apparentemente memoria utilizzata da un programma può aumentare, ma mai ridursi. Ho pensato che forse la memoria sarebbe davvero essere rilasciato per altri processi in situazioni critiche, come ad esempio quando non c'è più memoria disponibile. Dopo tutto, che senso avrebbe lasciare che un programma di mantenere la propria memoria per sempre, quando altri processi stanno chiedendo per essa? Così ho assegnata di nuovo il 30MB, e mentre deallocando li Ho eseguito un memtester quanta più memoria fisica ho potuto. Mi aspettavo di vedere la mano del software la sua memoria memtester. Ma indovinare, non è successo!

Ho fatto una breve screencast che mostra la cosa in azione:

Elimina esempio memoria

Per essere onesti al 100%, vi era una situazione in cui qualcosa è accaduto. Quando ho provato memtester con oltre la memoria fisica disponibile nel bel mezzo del processo di deallocazione del mio programma, la memoria utilizzata da mio programma è sceso a circa 3 MB. Il processo è stato ucciso memtester automaticamente, però, e quello che è successo è stato ancora più sorprendente! L'utilizzo della memoria del mio programma è aumentata a ogni eliminare chiamare! Era proprio come se Ubuntu è stata restaurando tutta la sua memoria indietro dopo l'incidente memtester.

  

Tratto da    http://www.thecrowned.org/c-delete-operator- davvero-frees memoria

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top