简体   繁体   English

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

[英]Why should avoid singleton in C++

People use singleton everywhere. 人们到处都使用单身人士。 Read some threads recently from stackoverflow that singleton should be avoided in C++, but not clear why is that. 最近从stackoverflow读取了一些线程,在C ++中应避免使用单例,但不清楚为什么会这样。

Some might worry about memory leak with undeleted pointers, things such as exceptions will skip the memory recycle codes. 有些人可能担心使用未删除指针的内存泄漏,例如异常会跳过内存回收代码。 But will the auto_ptr solve this problem? 但是auto_ptr会解决这个问题吗?

In general, as mentioned in another answer, you should avoid mutable global data. 通常,如另一个答案所述,您应该避免可变的全局数据。 It introduces a difficulty in tracking code side effects. 它引入了跟踪代码副作用的难度。

However your question is specifically about C++. 但是你的问题是关于C ++的。 You could, for instance, have global immutable data that is worth sharing in a singleton. 例如,您可以拥有值得在单例中共享的全局不可变数据。 In C++, specifically, it's nearly impossible to safely initialize a singleton in a multithreaded environment. 特别是在C ++中,在多线程环境中安全地初始化单例几乎是不可能的。

Multithreaded Environment 多线程环境

You can use the "construct on first use" idiom to make sure the singleton is properly initialized exactly by the time it is needed: http://www.parashift.com/c++-faq-lite/static-init-order.html . 您可以使用“首次使用时构造”这个习惯用法来确保单身人士在需要时正确初始化: http//www.parashift.com/c++-faq-lite/static-init-order.html

However, what happens if you have 2 (or more) threads which all try to access the singleton for the first time, at exactly the same time ? 但是,如果你有2个(或更多)线程都是第一次尝试访问单例,那么会发生什么呢? This scenario is not as far fetched as it seems, if the shared immutable data is data required by your calculateSomeData thread, and you initialize several of these threads at the same time. 如果共享的不可变数据是calculateSomeData线程所需的数据,并且您同时初始化其中几个线程,则此方案并不像看起来那么遥远。

Reading the discussion linked above in the C++ FAQ Lite, you can see that it's a complex question in the first place. 阅读上面在C ++ FAQ Lite中链接的讨论,你可以看到它首先是一个复杂的问题。 Adding threads makes it much harder. 添加线程使得它变得更加困难。

On Linux, with gcc, the compiler solves this problem for you - statics are initialized within a mutex and the code is made safe for you. 在Linux上,使用gcc,编译器为您解决了这个问题 - 静态函数在互斥锁中初始化,代码对您来说是安全的。 This is an enhancement, the standard requires no such behavior. 这是一种增强,标准不需要这样的行为。

In MSVC the compiler does not provide this utility for you and you get a crash instead. 在MSVC中,编译器不会为您提供此实用程序,而是会发生崩溃。 You may think "that's ok, I'll just put a mutex around my first use initialization!" 你可能会认为“没关系,我只是在我第一次使用初始化时添加一个互斥量!” However, the mutex itself suffers from exactly the same problem, itself needing to be static. 但是,互斥锁本身也存在完全相同的问题,本身需要是静态的。

The only way to make sure your singleton is safe for threaded use is to initialize it very early in the program before any threads are started. 确保单例对于线程使用是安全的唯一方法是在任何线程启动之前在程序的早期初始化它。 This can be accomplished with a trick that causes the singleton to be initialized before main is called. 这可以通过一个技巧来完成,该技巧导致在调用main 之前初始化单例。

Singletons That Rely on Other Singletons 依赖其他单身人士的单身人士

This problem can be mostly solved with the construct on first use idiom, but if you have the problem of initializing them before any threads are initialized, you can potentially introduce new problems. 这个问题可以通过第一次使用习惯用法的构造来解决,但是如果你在初始化任何线程之前有初始化它们的问题,你可能会引入新的问题。

Cross-platform Compatibility 跨平台兼容性

If you plan on using your code on more than one platform, and compile shared libraries, expect some issues. 如果您计划在多个平台上使用代码,并编译共享库,那么可能会遇到一些问题。 Because there is no C++ ABI interface specified, each compiler and platform handles global statics differently. 由于没有指定C ++ ABI接口,因此每个编译器和平台以不同方式处理全局静态。 For instance, unless the symbols are explicitly exported in MSVC, each DLL will have its own instance of the singleton. 例如,除非在MSVC中显式导出符号,否则每个DLL都将拥有自己的单例实例。 On Linux, the singletons will be implicitly shared between shared libraries. 在Linux上,单例将在共享库之间隐式共享。

避免使用可变全局变量,无论它们是否是单例,因为它们引入了无约束的通信线:您不知道代码的哪个部分影响其他部分,或何时发生。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM