2013-07-05 6 views
7

NOTA: sono interessato soprattutto a C#, Java e C++, ma poiché questa è la domanda più accademica che qualsiasi lingua possa fare.E 'possibile ad esempio distruggere/cancellare sé stessi?

So che questo problema è risolvibile dall'esterno, utilizzando metodi appropriati di determinate lingue (chiamando free, Dispose o rimuovendo tutti i riferimenti all'istanza).

La mia idea è di creare un'istanza e, nel costruttore, avviare il timer privato. Alla fine del timer chiamerà un metodo di istanza e distruggerà la variabile.

Penso che in C# dovrebbe essere possibile chiamare Dispose su sé, quando è implementato lo IDisposable, ma ciò non distruggerebbe l'instace.

In C++ potrei chiamare lo destructor, ma questo porterebbe alla perdita di memoria, in più è davvero una cattiva pratica.

In Java non ho idea, assegnando a this non è possibile in quanto è il campo final.

Quindi c'è un modo, ad esempio, per distruggere se stessi?

+0

in C# penso sia sufficiente per indirizzare l'istanza su null –

+0

Normalmente il GC in .NET svolge un ottimo lavoro da solo. A meno che non crei la tua perdita di memoria _own_ mantenendo un oggetto attorno staticamente (o in altro modo), allora dovrebbe essere rimosso alla fine. Plausibilmente, è possibile utilizzare un metodo factory che non restituisca un riferimento diretto all'oggetto, ma un riferimento debole. Probabilmente ancora non aiuta molto; puoi ancora recuperare un riferimento forte tramite il riferimento debole. Forse la domanda migliore è: che problema stai cercando di risolvere? –

+1

Dipende da cosa intendi per "destroy/delete" in Java. Puoi chiamare qualsiasi metodo su "questo" - che è equivalente ad es. chiamando Dispose() su un oggetto in C#. Se vuoi dire che vuoi che l'oggetto sia spazzato via, devi solo cancellare tutti i riferimenti ad esso e aspettare che il garbage collector lo liberi. –

risposta

7

La tua domanda è molto interessante, e non conosco altro modo per farlo in C# ma per forzare dall'interno dell'istanza la sua distruzione dall'esterno. Quindi questo è quello che mi è venuto in mente per verificare se è possibile. È possibile creare la classe Foo, che ha un evento che viene generato quando scade l'intervallo specifico del timer. La classe registrata per quell'evento (Bar) all'interno dell'evento annulla la registrazione dell'evento e imposta il riferimento dell'istanza su null. Questo è come lo farei, testato e funziona.

public class Foo 
{ 
    public delegate void SelfDestroyer(object sender, EventArgs ea); 

    public event SelfDestroyer DestroyMe; 

    Timer t; 

    public Foo() 
    { 
     t = new Timer(); 
     t.Interval = 2000; 
     t.Tick += t_Tick; 
     t.Start(); 
    } 

    void t_Tick(object sender, EventArgs e) 
    { 
     OnDestroyMe(); 
    } 

    public void OnDestroyMe() 
    { 
     SelfDestroyer temp = DestroyMe; 
     if (temp != null) 
     { 
      temp(this, new EventArgs()); 
     } 
    } 
} 

public class Bar 
{ 
    Foo foo; 
    public Bar() 
    { 
     foo = new Foo(); 
     foo.DestroyMe += foo_DestroyMe; 
    } 

    void foo_DestroyMe(object sender, EventArgs ea) 
    { 
     foo.DestroyMe -= foo_DestroyMe; 
     foo = null; 
    } 
} 

E al fine di verificare ciò, è possibile impostare un clic sul pulsante all'interno di un modulo, qualcosa di simile, e controllare nel debugger:

Bar bar = null; 
private void button2_Click(object sender, EventArgs e) 
{ 
     if(bar==null) 
      bar = new Bar(); 
} 

Così la prossima volta, quando si fa clic sul pulsante, sarà possibile vedere che l'istanza Bar esiste ancora ma l'istanza al suo interno è nullo sebbene sia stata creata all'interno del costruttore di Bar.

2

No, non è possibile ottenere ciò che si sta tentando di fare in C#.

Se si considera un esempio:

public class Kamikadze { 

    ......    
    private void TimerTick(..) 
    { 
     .... 
     if(itsTime) { 
      DestroyMe(); 
     } 
    } 

    ..... 
} 


var kamikadze = new Kamikadze(); 

dopo un po 'DestroyMe() saranno chiamati che pulisce dati interni.

Ma il riferimento kamikadze (puntatore se lo si desidera) è ancora valido e punta a quella posizione di memoria, quindi GC non farà nulla, non lo ritirerà, e l'istanza di Kamikadze resterà nella memoria.

3

C++: se un oggetto è stato assegnato dinamicamente, può cancellare il suo puntatore nella propria funzione, a condizione che questo puntatore non venga mai più utilizzato dopo quel punto.

0

In C++, le istanze suicidi sono parte integrante del modello di macchina a stati finiti:

//Context class contains a pointer to a State object. 

void BattleshipGame::SetGameState(IState* state) { 
    game_state = state; 
} 

void BattleshipGame::Loss() { 
    game_state->Loss(this); 
} 

void BattleshipGame::Idle() { 
    game_state->Idle(this); 
} 

void BattleshipGame::FlyBy() { 
    game_state->FlyBy(this); 
} 

void BattleshipGame::Attack() { 
    game_state->Attack(this); 
} 

void BattleshipGame::Win() { 
    game_state->Win(this); 
} 

void BattleshipGame::Load() { 
    game_state->Loading(this); 
} 

//State base class contains methods for switching to every state. 
class IState { 
public: 
    virtual void Loading(BattleshipGame* context); 
    virtual void Idle(BattleshipGame* context); 
    virtual void FlyBy(BattleshipGame* context); 
    virtual void Attack(BattleshipGame* context); 
    virtual void Win(BattleshipGame* context); 
    virtual void Loss(BattleshipGame* context); 
protected: 
private: 

}; 

//Implementations in the State base class are defined, but empty. 

//Derived States only call what they need: 

void StateIdle::Loss(BattleshipGame* context) { 
    //context->SetGameState(new StateLoss()); 
    context->SetGameState(new StateLoss(context)); 
    delete this; 
} 

void StateIdle::Idle(BattleshipGame* context) { 
    context->SetGameState(new StateIdle()); 
    delete this; 
} 

void StateIdle::FlyBy(BattleshipGame* context) { 
    context->SetGameState(new StateFlyBy()); 
    delete this; 
} 

void StateIdle::Win(BattleshipGame* context) { 
    context->SetGameState(new StateWin()); 
    delete this; 
} 

//Similar design for all other states... 
1

La cosa più vicina in C# che mi viene in mente:

sulla creazione, ogni negozi oggetto A riferimento a se stesso nella radice del GC, ad es inserendo il riferimento in una lista statica di classe. Al di fuori della classe, nessuno è autorizzato a memorizzare riferimenti (forti) all'oggetto. Ognuno usa uno WeakReference e controlla se lo Target è ancora IsAlive prima di toccare l'oggetto. In questo modo, l'unica cosa che mantiene vivo l'oggetto è il riferimento statico.

Quando l'oggetto decide di uccidersi, rimuove semplicemente il riferimento dall'elenco. Prima o poi, il GC raccoglie l'oggetto. Oppure, se sei davvero impaziente, chiama lo GC.Collect() (ahi!).

Ma io davvero vorrei sconsigliamo questa soluzione!

È molto meglio mettere un po 'di flag nella classe/oggetto per segnalare se è ancora vivo e fare in modo che tutti controllino questo flag prima di utilizzare l'oggetto. Questo può essere combinato con la soluzione IDisposable.

Problemi correlati