为什么要在C ++中避免使用单例

时间:2014-08-17 01:55:11

标签: c++ design-patterns singleton

人们到处都使用单身人士。最近从stackoverflow读取了一些线程,在C ++中应避免使用单例,但不清楚为什么会这样。

有些人可能担心使用未删除指针的内存泄漏,例如异常会跳过内存回收代码。但是auto_ptr会解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

通常,如另一个答案所述,您应该避免可变的全局数据。它引入了跟踪代码副作用的难度。

但是你的问题是关于C ++的。例如,您可以拥有值得在单例中共享的全局不可变数据。特别是在C ++中,在多线程环境中安全地初始化单例几乎是不可能的。

多线程环境

您可以在首次使用时使用"构建"成语以确保单身人士在需要的时候正确初始化:http://www.parashift.com/c++-faq-lite/static-init-order.html

然而,如果你有两个(或更多)线程都是第一次尝试访问单身,那么会发生什么呢??如果共享不可变数据是calculateSomeData线程所需的数据,并且您同时初始化其中几个线程,则此方案不像看起来那么遥远。

阅读上面在C ++ FAQ Lite中链接的讨论,您可以看到它首先是一个复杂的问题。添加线程会让事情变得更加困难。

在Linux上,使用gcc,编译器为您解决了这个问题 - 静态函数在互斥锁中初始化,代码对您来说是安全的。这是一种增强,标准不需要这样的行为。

在MSVC中,编译器不会为您提供此实用程序,而是会发生崩溃。你可能会认为,没关系,我只是在首次使用初始化时添加一个互斥量!"但是,互斥锁本身也存在完全相同的问题,本身需要是静态的。

确保单例对于线程使用是安全的唯一方法是在任何线程启动之前在程序的早期初始化它。这可以通过一个技巧来完成,这个技巧会导致在调用 main之前对单例进行初始化

依赖其他单身人士的单身人士

这个问题可以通过第一次使用习惯用法的构造来解决,但是如果你在初始化任何线程之前初始化它们的问题,你可能会引入新的问题。

跨平台兼容性

如果您计划在多个平台上使用您的代码,并编译共享库,则会遇到一些问题。由于没有指定C ++ ABI接口,因此每个编译器和平台以不同方式处理全局静态。例如,除非在MSVC中显式导出符号,否则每个DLL都将拥有自己的单例实例。在Linux上,单例将在共享库之间隐式共享。

答案 1 :(得分:1)

避免使用可变的全局变量,无论他们是否是单身人士,因为他们引入了无约束的沟通渠道:你不知道代码的哪一部分正在影响其他部分,或何时发生。