我对此代码有疑问>任何讨论都会对理解这些事情非常有帮助:
class Singleton
{
private:
static Singleton *single;
Singleton() {}
~Singleton() {}
public:
static Singleton* getInstance()
{
if (!single)
single = new Singleton();
return single;
}
void method()
{
cout << "Method of the singleton class" << endl;
}
static void destroy()
{
delete single;
single = NULL;
}
};
Singleton* Singleton::single = NULL;
int main()
{
Singleton *sc2;
sc2 = Singleton::getInstance(); // sc2 is pointing to some memory location
{
Singleton *sc1 = Singleton::getInstance(); // sc1 and sc2 pointing to same memory location
sc1->method();
Singleton::destroy(); // memory location deleted.
cout << sc1;
}
sc2->method(); // ??? how this is working fine??
return 0;
}
在这个块中,我们正在删除“Singleton :: destroy()”;
中的内存{
Singleton *sc1 = Singleton::getInstance();
sc1->method();
Singleton::destroy();
cout << sc1;
}
然后如何调用“sc2-&gt; method();”是成功的吗?
Devesh
答案 0 :(得分:2)
为什么会有效?
因为您正在调用的函数是静态定义的,所以不需要this指针来调用它,函数本身也不使用this指针。因此,该功能没有理由崩溃。
但是,正如您所提到的,该课程被滥用了。
仍允许使用destroy()函数的一种更安全的方法是对Singleton指针使用shared_ptr&lt;&gt;()。这样,破坏就变成了:
single.reset();
如果其他人仍有指针,它仍然有效。只有在再次调用getInstance()时才会出现问题。那时你有两个版本的“单身人士”。虽然你有另一种方法可以解决这个问题:一旦调用了destroy,你就可以阻止对getInstance()的任何调用。
getInstance() ... if(destroyed) throw std::runtime_error("singleton destroyed"); ...
destroy() ... destroyed = true; ...
<强>更新强>
根据g ++ / objdump -d有一个方法调用程序集的副本(在Linux下,虽然它也应该在cygwin中工作):
400978: 48 8b 45 f0 mov -0x10(%rbp),%rax
40097c: 48 89 c7 mov %rax,%rdi
40097f: e8 ae 00 00 00 callq 400a32 <_ZN9Singleton6methodEv>
(P.S.objdump用通常的INTEL语法反转的寄存器进行反汇编。)
正如我们所看到的,编译器使用“callq
”。 this
指针位于%rax
。 “callq
”不使用%rax
。就汇编代码而言,该函数目前是静态的。
在method()
内,未使用%rax
,因此无论其价值如何都无关紧要:
0000000000400a32 <_ZN9Singleton6methodEv>:
400a32: 55 push %rbp
400a33: 48 89 e5 mov %rsp,%rbp
400a36: 48 83 ec 10 sub $0x10,%rsp
400a3a: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400a3e: be 44 0b 40 00 mov $0x400b44,%esi
400a43: bf 80 10 60 00 mov $0x601080,%edi
400a48: e8 b3 fd ff ff callq 400800 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400a4d: be 30 08 40 00 mov $0x400830,%esi
400a52: 48 89 c7 mov %rax,%rdi
400a55: e8 c6 fd ff ff callq 400820 <_ZNSolsEPFRSoS_E@plt>
400a5a: c9 leaveq
400a5b: c3 retq
答案 1 :(得分:1)
简要总结Jesse的链接说明:
你很幸运。 sc2
仍然指向那个旧实例。它的内存被释放,但这并不意味着它被清除了。如果访问该内存,则结果未定义。它似乎可以工作(就像它对你一样),它可能会遇到一些可能会提醒你注意问题的调试功能,或者它可能会使计算机长大并跑出门。这是未定义的,由你来确保它不会发生。