代码之家  ›  专栏  ›  技术社区  ›  wilhelmtell

你如何在一个单独的班级和一个未命名的班级之间做出选择?

  •  3
  • wilhelmtell  · 技术社区  · 16 年前

    我会用这样的单件:

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

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

    single.do_it();
    

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

    那么,为什么你会选择单身而不是不知名的班级呢?

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

    class {
        // ...
    }single;
    

    我也可以这样定义它:

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

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

    8 回复  |  直到 15 年前
        1
  •  8
  •   Johannes Schaub - litb    15 年前

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

    class { } single;
    int main() { }
    

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

        2
  •  4
  •   Roddy    16 年前

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

    作为一个例子,我的很多代码都使用一个日志记录器singleton,其中日志消息被写入其中。这在许多月球之前就作为一个古老的“全球”开始了,但在被咬后,在建造之前尝试使用它,现在它变成了一个独生子:

    在…之前

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

    …之后

     Logger &getLogger()
     {
       static Logger logger_;
       return logger_;
     }
    
     getLogger().write("Something bad happened...");
    

    我已经阅读了“单身人士是坏”的帖子,但没有看到任何人建议C++更好的选择。

        3
  •  2
  •   David Norman    16 年前

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

        4
  •  1
  •   Dustin Getz sunsations    16 年前

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

        5
  •  1
  •   Head Geek    16 年前

    虽然方便,但单件通常 a bad idea . 见 this page 替换设计。

        6
  •  1
  •   zarzych    16 年前

    从你的问题中,我可以看出你并不真正理解单例模式的本质和目的。

    如果你想的话,可以用单件 全球的 对象可由许多“客户端”访问,您希望确保只创建此对象的一个实例。 以记录器对象为例。您希望能够从代码的任何部分进行日志记录,但是项目中应该只有一个日志记录器。这是单身的好地方。

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

        7
  •  0
  •   Dustin Getz sunsations    16 年前

    如果(除了错误冗长性)没有行为差异,全局实例需要1个额外的loc,那么单例实例将需要一组非平凡的样板文件。吻

        8
  •  0
  •   Ray Tayek    16 年前

    使用单件。使用const。初始化它们 全部的 在里面 上帝班。注意并避免静态初始化顺序错误: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12