【发布时间】:2021-07-19 23:38:50
【问题描述】:
我对单例模式在 C# 和 C++ 之间释放对象内存有疑问; 这里是 C++ 代码:
#include<iostream>
using namespace std;
class Rocket
{
private:
Rocket() { speed = 100; }
~Rocket() {}
static Rocket* ms_rocket;
public:
int speed;
static Rocket*ShareRocket()
{
if (ms_rocket == NULL)
ms_rocket = new Rocket();
return ms_rocket;
}
static void Close()
{
if (ms_rocket != NULL)
delete ms_rocket;
}
};
Rocket *Rocket::ms_rocket = NULL;
int main()
{
Rocket* p = Rocket::ShareRocket();
p->speed = 100;
cout << p->speed << endl;
Rocket::Close();
cout << p->speed << endl;
getchar();
}
当我使用Rocket::Close()时,ms_rocket指向的内存空间会被释放,ms_rocket变成一个野指针,第二个“cout 在C#中,我认为当我使用Dispose()时,内存(B单例中的'a'对象)会被释放,但是在第二次访问时,年龄值不应该是100,而静态变量'a ' 将变得像一个野指针。
谁能告诉我为什么? class A : IDisposable
{
public int age;
public A() { }
public void Run()
{
Console.WriteLine("Run");
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
Console.WriteLine("A is release");
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
class B
{
static A a;
private B() { }
public static A Intance
{
get
{
if (a == null)
a = new A();
return a;
}
}
}
class Class1
{
public static void Main(string[] args)
{
A a = B.Intance;
a.age =100;
Console.WriteLine(a.age);
a.Dispose();
A a1 = B.Intance;
Console.WriteLine(a1.age);
Console.Read();
}
}
【问题讨论】:
-
C# 有一个 garbage collector 可以在需要的时候删除东西,在 C++ 中,你是 garbage collector 并且你决定什么时候删除以及删除什么,所以基本上我猜在这种情况下 garbage collector 没有释放你正在谈论的内存。此外,在 C++ 中,如果您尝试将其打印出来,您也可能具有相同的值,但在这种情况下,它只是一个未定义的行为,而不是一些有效的东西。
-
Karen 所说的,但 C# 中的 GC 确实有一个方法,在第一次传递中它标记对象以进行垃圾回收。即使您致电
GC.Collect,它也只会标记第一次传递的项目。在随后的传递中,它最终会为它释放内存。 -
当您
delete时,您是在说:“我不再需要它并保证不再使用它。”如果你违背了诺言,那是你的责任。因为任何检查以确保您遵守诺言都会减慢遵守诺言的程序,而这都是正确编写的程序,所以 C++ 不需要检查。 -
@KarenMelikyan,@jzian,Dispose() 也不会发布任何内容。这样您就可以对非托管资源进行清理。根据您的示例,如果您希望 GarbageCollector 最终清理 A,则需要通过某种方式在 B 上将其设置为 null。IE,将设置器添加到您执行操作的 B.Instance 属性:
B.Instance = null。 -
旁注:A generally better, thread-safe C++ Singleton。请注意完全没有
new和delete。这偏离了问题的代码,因为一旦创建,只有程序退出才能销毁对象。另一方面,您不需要 dispose 方法。已经为您完成了。