C++ 您如何在单例类和未命名类之间进行选择?

C++ 您如何在单例类和未命名类之间进行选择?,c++,singleton,C++,Singleton,我会用这样一个单身汉: Singleton* single = Singleton::instance(); single->do_it(); single.do_it(); 我会使用这样一个未命名的类: Singleton* single = Singleton::instance(); single->do_it(); single.do_it(); 我觉得单例模式除了具有可读的错误消息之外,与未命名类相比没有任何优势。使用单例比使用未命名的类对象更笨拙:首先,客户端必须

我会用这样一个单身汉:

Singleton* single = Singleton::instance();
single->do_it();
single.do_it();
我会使用这样一个未命名的类:

Singleton* single = Singleton::instance();
single->do_it();
single.do_it();
我觉得单例模式除了具有可读的错误消息之外,与未命名类相比没有任何优势。使用单例比使用未命名的类对象更笨拙:首先,客户端必须首先获得实例的句柄;第二,实现代码> Stutelon::Stand()/Cux>可能需要考虑并发性。

那么,为什么和如何选择一个单身而不是一个未命名的类呢

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

class {
    // ...
}single;
我也可以这样定义它:

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

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

即使这样更改代码可能不会影响代码生成,也是一个糟糕的想法。迟早有人会在调试或发布中进行一个小调整,生成不同的代码,然后出现无法在调试版本中复制的发布崩溃。

如果(除了错误详细性)没有行为差异,全局实例需要1个额外的LOC,一个单身汉需要一堆非平凡的样板。KISS

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

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


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

单例虽然方便,但通常是。请参阅替换设计。

< P>当然,C++中使用单点对象的主要原因是通过使用实例方法中的“惰性构造”来控制初始化顺序。p> 作为一个例子,我的大部分代码都使用了一个日志记录器单例,日志消息就是在其中写入的。这在很多月前就开始作为一个很好的“全球”卫星,但在建造之前尝试使用它之后,它现在是一个单子:

以前

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

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

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

<>我读过一些“单身人士是坏的”帖子,但没有看到有人建议一个更好的C++选项。p> 从您的问题中,我可以看出您并不真正理解Singleton模式的本质和目的

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


您的示例看起来好像创建了一个小范围的局部对象。因为这个单身汉是不需要的。它使代码更加清晰易读。

使用单例。使用常量。在一个上帝类中初始化它们。请注意并避免静态初始化顺序的失败:

显然,下一个标准将允许未命名类型作为模板参数:是的,他们希望允许。我认为他们允许它的一个主要因素是,它还将有lambda,它们实际上是未命名类型的对象。不能将lambda传递给模板化函数将是一件遗憾的事情。仅此一个原因就足够了。我无法想象在没有lambdas的情况下使用标准算法(不,等等,我可以)+1利特。似乎一周都没有发现C++中的一个新的黑暗角落…你的意思是“单一的类型”,而不是Obj.单身者一般都不坏!您只需要具备软件体系结构的经验就可以决定哪些组件应该成为单体组件。使用单例应该是一个有意识的设计选择,不能多也不能少。单例通常是不好的。它们通常在不符合要求时使用。(单例是指当它有多个实例时会导致问题,以及当您需要全局访问对象时。Roddy的代码严格来说不是单例,因为它不会阻止我创建多个记录器,如果我想的话。(我认为这是一件非常好的事情)。所以您已经在使用“更好的选择”。)不,未命名的类对象是全局对象。我所需要做的就是将定义放在头文件中,并将其包含在我想要的任何地方。