这个Singleton实现有什么问题
What is wrong with this Singleton implementation?
这个想法是在程序结束时删除C++中的Singleton。我们在课堂上学习了这种实现方法:
class Singleton
{
private:
static Singleton* the_singleton;
protected:
Singleton()
{
static Keeper keeper(this);
/*CONSTRUCTION CODE*/
}
virtual ~Singleton()
{
/*DESTRUCTION CODE*/
}
public:
class Keeper
{
private:
Singleton* m_logger;
public:
Keeper(Singleton* logger):m_logger(logger){}
~Keeper()
{
delete m_logger;
}
};
friend class Singleton::Keeper;
static Singleton* GetInstance();
{
if (!the_singleton)
the_singleton = new Singleton();
return the_singleton;
}
};
Singleton* Singleton::the_singleton = NULL;
其想法是,在第一次创建Singleton时,将在Singleton的C'tor中创建一个静态Keeper对象,一旦程序结束,该Keeper将被销毁,进而销毁它所指向的Singleton实例。
现在,这个方法对我来说似乎很麻烦,所以我建议放弃keeper类,将Singleton的实例作为getInstance方法的静态对象:
<!-- language: c++ -->
class Singleton
{
protected:
Singleton()
{
/*CONSTRUCTION CODE*/
}
~Singleton()
{
/*DESTRUCTION CODE*/
}
public:
static Singleton &getInstance()
{
static Singleton instance;
return instance;
}
/*OBJECT FUNCTIONALITY*/
};
这样,Singleton在对getInstance方法的第一次调用时构造,并在程序结束后销毁。不需要那种守门员级别。
我测试了它,它运行得很好——辛格尔顿号在正确的地方被建造和摧毁。然而,我的TA说这个模式是错误的,尽管他记不起它到底出了什么问题。所以我希望这里有人以前遇到过这个实现,可以告诉我它出了什么错。
这是错误的,但您的修改并没有引入问题——它们一直都存在。
目前还没有强制执行singleton属性。构造函数需要是私有的,而不是受保护的,以确保不会创建其他实例。
除此之外,原始代码在多线程场景中完全不可用。您的将从C++0x开始工作。
如果TA的keeper对象已经将全局指针重置回NULL,那么在程序清理期间,如果需要,他的实现将能够(在单线程环境中)重新创建单例。阅读C++中的Singleton模式。但这仍然是singleton的一个新实例,这几乎和在调用其析构函数后使用singleton一样出乎意料。
然而,他忽略了这一点,所以在keeper删除singleton之后,他会很高兴地在程序关闭期间使用无效指针。在您的系统中,即使对象的生存期已经结束,至少内存区域仍然有效。
当然,你会因为使用改进版本而被扣分,这只是表明课程的目的不是教你C++,而是助教对C++的误解。
它根本没有问题。IMHO,"守护者"这件事对这个应用程序来说太疯狂了。
在少数情况下,这可能是有道理的。例如,如果Singleton必须接受构造函数参数,那么静态分配它可能是不可能的。或者,如果它的构造函数可能失败,那么更简单的方法将不允许您恢复或重试。因此,在某些情况下,可能需要做一些更复杂的事情。然而,在许多情况下,这是不必要的。
"至少在你的记忆区域即使对象的生存期已结束"
这是真的,但对程序执行来说并不意味着什么——析构函数可能会使内存区域处于使用它无论如何都会失败的状态——例如释放内部缓冲区。在对象的析构函数被调用后,您永远不应该使用它——如果您想从其他静态/全局对象的析构函数中使用您的singleton,那么您不能保证这些析构函数的调用顺序。
如果您使用静态对象,而其他一些析构函数会在它被销毁后尝试使用它,那么将无法检查singleton是否仍然存在。若您使用将指针设置为NULL的keeper对象,那个么在其他析构函数中,您至少可以检查NULL指针,并决定根本不使用singleton。这样,尽管你可能会失败,但至少你不会得到神秘的"分段错误"或"访问违规",程序将避免异常终止。
编辑:您需要记住,在管理员将此字段设置为NULL后,修改您的访问器函数,使其不再创建对象——也许是额外的静态布尔,说明对象是否已被释放?
- 警告处理为错误这里有什么问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 当我尝试添加 2 个大字符串时,我无法弄清楚出了什么问题
- 违反const正确性:我应该现实地期待什么问题
- 这个带有模板<类 Vector 的C++代码片段有什么问题>
- 我的逻辑反转字符串中的元音有什么问题?
- 需要以下代码的帮助,下面的代码有什么问题
- 常量公共成员有什么问题?
- 以下代码中的函数模板有什么问题?
- 这个返回元素位置的基于循环的函数有什么问题?
- creat_list2功能有什么问题?
- 格式说明符C++有什么问题
- 任何人都可以告诉我我的 C++ 代码出了什么问题?
- 从 argv[1] 转换为字符 * 字符串后有什么问题?
- 我的堆栈和库存清单程序的结构有什么问题?
- 此工厂功能有什么问题?
- 以下 C++ 代码有什么问题?
- 数组为此合并排序函数提供了正确的输出,但向量给出了不正确的输出.出了什么问题?
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 它解决了什么问题,对于非真空初始化,生命周期在初始化之前就开始了