有没有一种方法可以在 C++ 中实现单例对象:
- 以线程安全的方式延迟构造(两个线程可能同时是单例的第一个用户 - 它仍然应该只构造一次)。
- 不依赖于预先构造的静态变量(因此在构造静态变量期间单例对象本身可以安全使用)。
(我不太了解我的C++,但是在执行任何代码之前是否会初始化整型和常量静态变量(即,甚至在执行静态构造函数之前 - 它们的值可能已经在程序中“初始化”) image)?如果是这样 - 也许可以利用它来实现单例互斥体 - 这反过来又可以用来保护真正单例的创建..)
太棒了,看来我现在有几个很好的答案了(可惜我不能将 2 或 3 标记为答案)。似乎有两种广泛的解决方案:
- 使用 POD 静态变量的静态初始化(而不是动态初始化),并使用内置原子指令实现我自己的互斥体。这就是我在问题中暗示的解决方案类型,我相信我已经知道了。
- 使用其他一些库函数,例如线程一次 http://opengroup.org/onlinepubs/007908799/xsh/pthread_once.html or 升压::call_once http://www.boost.org/doc/libs/1_33_1/doc/html/call_once.html。这些我当然不知道 - 并且非常感谢发布的答案。
基本上,您要求同步创建单例,而不使用任何同步(先前构造的变量)。一般来说,不,这是不可能的。您需要一些可用于同步的东西。
至于您的其他问题,是的,可以静态初始化的静态变量(即不需要运行时代码)保证在执行其他代码之前初始化。这使得可以使用静态初始化的互斥体来同步单例的创建。
从2003年修订的C++标准开始:
具有静态存储持续时间(3.7.1)的对象应在任何其他初始化发生之前进行零初始化(8.5)。零初始化和用常量表达式初始化统称为静态初始化;所有其他初始化都是动态初始化。具有用常量表达式(5.19)初始化的静态存储持续时间的 POD 类型(3.9)的对象应在任何动态初始化发生之前进行初始化。在同一翻译单元的命名空间范围内定义并动态初始化的静态存储持续时间的对象应按照其定义在翻译单元中出现的顺序进行初始化。
If you know如果您将在其他静态对象的初始化期间使用此单例,我想您会发现同步不是问题。据我所知,所有主要编译器都在单个线程中初始化静态对象,因此静态初始化期间的线程安全。您可以将单例指针声明为 NULL,然后在使用它之前检查它是否已初始化。
但是,这假设您know您将在静态初始化期间使用此单例。标准也不能保证这一点,因此如果您想完全安全,请使用静态初始化的互斥体。
编辑:克里斯关于使用原子比较和交换的建议肯定会起作用。如果可移植性不是问题(并且创建额外的临时单例也不是问题),那么它是一个开销稍低的解决方案。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)