有可能销毁/删除自身吗?

17

注意:我最感兴趣的是C#,Java和C ++,但由于这是更加学术性的问题,任何语言都可以。

我知道可以通过使用给定语言的适当方法(调用 free , Dispose 或通过删除对实例的所有引用)来解决此问题。

我的想法是创建一个实例,在构造函数中启动私有计时器。 当计时器结束时,它将调用某些实例方法并销毁变量。

我认为在C#中,如果实现了IDisposable,应该可以调用self上的 Dispose ,但这不会销毁实例。

在C ++中,我可以调用析构函数,但这会导致内存泄漏,而且这是非常糟糕的做法。

在Java中,我不知道如何做,因为将this赋值给final字段是不可能的。

那么,是否有一种方法可以销毁自身实例?


在C#中,我认为将实例指向null就足够了。 - Sebastian 506563
通常情况下,.NET中的GC自己做得很好。除非您通过静态(或其他方式)保留对象来创建自己的内存泄漏,否则它应该最终被删除。可能,您可以使用一个工厂方法,它不会返回对对象的直接引用,而是返回一个弱引用。这可能仍然没有太大帮助;您仍然可以通过弱引用检索到强引用。也许更好的问题是:您试图解决什么问题? - Chris Sinclair
1
这取决于你在Java中所说的“销毁/删除”的含义。你可以在this上调用任何方法 - 这相当于在C#中调用对象的Dispose()方法。如果你的意思是想让对象被垃圾回收,你只需要清除所有对它的引用,并等待垃圾回收器释放它即可。 - Alex MDC
在您的情况下,任何正在运行垂死实例的实例方法的线程应该发生什么? - Rob
8个回答

11

您的问题非常有趣,我不知道除了从实例内部强制销毁外,在C#中是否还有其他方法来实现这一点。因此,我想到了一个检查是否可能的方法。

您可以创建一个名为Foo的类,该类具有在定时器特定时间间隔到期时触发的事件。在事件中注册的类(Bar)会注销该事件并将实例的引用设置为null。这是我会这样做的方式,经过测试,它可以正常工作。

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;
    }
}

为了测试这个功能,您可以在表单中设置一个按钮点击事件,如下所示,并在调试器中检查它:

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

下次当您点击按钮时,您将能够看到Bar实例仍然存在,但其中的Foo实例为空,尽管它已经在Bar的构造函数中被创建。

3

C++:如果一个对象是动态分配的,它可以在自己的函数中删除它的this指针,前提是在那个点之后不再使用该this指针。


2
不,无法在C#中实现您尝试做的事情。
如果您考虑一个例子:
public class Kamikadze {

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

     .....
}


var kamikadze = new Kamikadze ();

过一段时间后,将调用DestroyMe(),这将清除内部数据。

但是引用kamikadze(如果您愿意,可以称之为指针)仍然有效,并且指向该内存位置,因此GC不会执行任何操作,也不会收集它,Kamikadze实例将继续存在于内存中。


1

1
我能想到的 C# 中最接近的东西是:
在创建时,每个对象将自己的引用存储在 GC 根中,例如通过将引用放入类静态列表中。在类外部,不允许任何人存储(强)对该对象的引用。每个人都使用 WeakReference,并在触摸对象之前检查 Target 是否仍然 IsAlive。这样,唯一使对象存活的是静态引用。
当对象决定杀死自己时,它只需从列表中删除引用。迟早,GC 会收集对象。或者,如果你真的很着急,调用 GC.Collect()(疼!)。
但我真的真的不建议使用这种解决方案!
更好的方法是在类/对象中放置一些标志,以表明它是否仍然存活,并在每个人使用对象之前检查此标志。这可以与 IDisposable 解决方案相结合。

0
我建议使用NFTLKEY。您可以轻松地从Nuget包中获取它。最重要的是,它是开源的: github项目 比这里的示例更容易理解。

0
在C++中,实例自杀是有限状态机模式的一个重要组成部分:
//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...

0

在C#中,你是对的,可以实现IDisposable,但诀窍是不要调用Dispose方法,而是使用using语句。

class Program
{
    static void Main(string[] args)
    {
        using (MyClass obj = new MyClass())
        {
            obj.SayHello();
        }

        // obj.SayHello(); // Error: The name 'obj' does not exist in the current context
    }
}

class MyClass : IDisposable
{
    public void SayHello()
    {
        Console.WriteLine("Hello");
    }

    public void Dispose()
    {
        // Do something (e.g: close some open connection, etc)
    }
}

参考资料:microsoft-docs/using-statement


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接