你如何在单身人士和未命名的阶级之间做出选择?

时间:2008-12-28 01:58:05

标签: c++ singleton

我会使用像这样的单身人士:

Singleton* single = Singleton::instance();
single->do_it();

我会使用这样一个未命名的类:

single.do_it();

我觉得Singleton模式除了具有可读错误消息之外没有优于未命名类的优势。使用单例比使用未命名的类对象更笨拙:首先,客户端必须首先获得实例的句柄;第二,Singleton::instance()的实现者可能需要考虑并发性。

那么为什么以及如何选择一个未命名类的单身?

作为附录,虽然未命名类的明显定义可能是

class {
    // ...
}single;

我可以这样定义:

#ifndef NDEBUG
class Singleton__ {   // readable error messages,
#else
class {               // unnamed, clients can't instantiate
#endif
    // ...
}single;

后一种方法具有可读编译器错误消息的优点,但在调试模式下不是单例。

8 个答案:

答案 0 :(得分:8)

我认为最重要的原因是你不能在命名空间范围内放入一个未命名的类。因此,以下内容无效(gcc接受,但警告。在严格模式下,comeau不接受):

class { } single;
int main() { }

single的类型具有 no 链接,因为无法在引用它的另一个范围内声明其名称(正是因为它没有名称)。但是使用它来声明single,其中具有链接(此处为外部)无效(3.5 / 8)。 single必须在main中本地定义,它将没有链接。您也无法将单个模板传递给函数模板,也不能拥有静态数据成员(因为无法定义它们)。所有这些限制使其或多或少不适用于替代单身人士。

答案 1 :(得分:4)

当然,在C ++中使用单例对象的主要原因是通过在实例方法中使用“延迟构造”来控制初始化顺序吗?

作为一个例子,我的大部分代码都使用记录器单例来写日志消息。这在许多年前开始是一个很好的旧“全球”,但是在被施工之前试图使用它之后被咬了一下,它现在是一个单身人士:

...前

logger.write("Something bad happened..."); // crash if logger not constructed

...后

 Logger &getLogger()
 {
   static Logger logger_;
   return logger_;
 }

 getLogger().write("Something bad happened...");

我已经阅读了常规的“单身人士不好”的帖子,但是没有人见过有人建议更好的替代C ++。

答案 2 :(得分:2)

您可以在标头中声明并在cxx中实现的单例类,因此可以跨cxx文件共享。你不能用未命名的类做到这一点,因为每个cxx都会尝试拥有自己的对象实例。

答案 3 :(得分:1)

改变代码,即使它可能不会影响代码生成也是一个糟糕的主意。迟早有人会做一个小调整,在调试或发布中生成不同的代码,然后你就会发现在调试版本中无法复制的版本崩溃。

答案 4 :(得分:1)

虽然方便,但单身人士通常a bad idea。有关替代设计,请参阅this page

答案 5 :(得分:1)

从你的问题我可以看出你并不真正了解Singleton模式的本质和目的。

如果您希望许多“客户”可以访问全局对象,并且您希望确保只创建此对象的一个​​实例,则使用单例。 以记录器对象为例。您希望能够从代码的任何部分进行记录,但项目中应该只有一个记录器。这是单身人士的理想场所。

您的示例看起来好像您创建了一个范围较小的本地对象。因为这不需要单身人士。它使代码更清晰,更容易阅读。

答案 6 :(得分:0)

如果(除了错误详细程度)没有行为差异,全局实例需要1个额外的LOC,单个将需要一堆非常重要的样板。 KISS

答案 7 :(得分:0)

使用单身人士。使用const。在一个上帝类中初始化它们 all 。注意并避免静态初始化命令fiasco:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12