关于C++中的两种单例模式

发布于 2024-12-03 04:15:27 字数 857 浏览 0 评论 0原文

当我寻找有关 C++ 单例模式的信息时,我总是找到这样的例子:

class Singleton
{
    public:
        ~Singleton() {
        }

        static Singleton* getInstance()
        {
            if(instance == NULL) {
                instance = new Singleton();
            }
            return instance;
        }

    protected:
        Singleton() {
        }

    private:
        static Singleton* instance;
};

Singleton* Singleton::instance = NULL;

但是这种单例似乎也可以工作:

class Singleton
{
    public:
        ~Singleton() {
        }

        static Singleton* getInstance()
        {
            return &instance;
        }

    protected:
        Singleton() {
        }

    private:
        static Singleton instance;
};

Singleton Singleton::instance;

我猜第二个单例是在程序开始时实例化的,与第一个不同,但这是唯一的区别吗?

为什么我们主要发现第一个?

When I look for informations about the singleton pattern for C++, I always find examples like this:

class Singleton
{
    public:
        ~Singleton() {
        }

        static Singleton* getInstance()
        {
            if(instance == NULL) {
                instance = new Singleton();
            }
            return instance;
        }

    protected:
        Singleton() {
        }

    private:
        static Singleton* instance;
};

Singleton* Singleton::instance = NULL;

But this kind of singleton also seems to work as well:

class Singleton
{
    public:
        ~Singleton() {
        }

        static Singleton* getInstance()
        {
            return &instance;
        }

    protected:
        Singleton() {
        }

    private:
        static Singleton instance;
};

Singleton Singleton::instance;

I guess that the second singleton is instantiated at the beginning of the program, unlike the first, but is it the only difference?

Why do we find mainly the first?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

牵强ㄟ 2024-12-10 04:15:27

http://www.parashift.com/c++-faq-lite /ctors.html#faq-10.14

静态初始化顺序失败是一个非常微妙且常见的问题
对 C++ 的误解。不幸的是,它很难被发现——
错误通常发生在 main() 开始之前。

简而言之,假设您有两个静态对象 x 和 y 存在于
单独的源文件,例如 x.cpp 和 y.cpp。进一步假设
y 对象的初始化(通常是 y 对象的构造函数)
调用 x 对象上的某些方法。

就是这样。就这么简单。

悲剧的是你有50%-50%的几率死亡。如果
x.cpp 的编译单元恰好首先被初始化,一切都是
出色地。但是如果 y.cpp 的编译单元首先被初始化,
那么 y 的初始化将在 x 的初始化之前运行,并且
你干杯了。例如,y 的构造函数可以调用 x 上的方法
对象,但 x 对象尚未构造。

您列出的第一种方法完全避免了这个问题。这被称为“首次使用惯用法”

这种方法的缺点是对象永远不会被破坏。
还有另一种技术可以解决这个问题,但它需要
小心使用,因为它创造了另一种可能性(同样
讨厌的)问题。

注意:在某些情况下,静态初始化顺序也会失败,
适用于内置/固有类型。

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14

The static initialization order fiasco is a very subtle and commonly
misunderstood aspect of C++. Unfortunately it's very hard to detect —
the errors often occur before main() begins.

In short, suppose you have two static objects x and y which exist in
separate source files, say x.cpp and y.cpp. Suppose further that the
initialization for the y object (typically the y object's constructor)
calls some method on the x object.

That's it. It's that simple.

The tragedy is that you have a 50%-50% chance of dying. If the
compilation unit for x.cpp happens to get initialized first, all is
well. But if the compilation unit for y.cpp get initialized first,
then y's initialization will get run before x's initialization, and
you're toast. E.g., y's constructor could call a method on the x
object, yet the x object hasn't yet been constructed.

The first method you listed avoids this problem completely. It's called the "construct on first use idiom"

The downside of this approach is that the object is never destructed.
There is another technique that answers this concern, but it needs to
be used with care since it creates the possibility of another (equally
nasty) problem.

Note: The static initialization order fiasco can also, in some cases,
apply to built-in/intrinsic types.

妥活 2024-12-10 04:15:27

第一个允许您删除实例,而第二个则不允许。但请注意,您的第一个示例不是线程安全的

The first one allows you to delete the instance while the second one does not. But please be aware that your first example is not thread safe

任性一次 2024-12-10 04:15:27

It's commonly known as the static initialization order fiasco. In summary, static instances at file scope are not necessarily initialized before explicit function calls that create one as in your first example.

猫卆 2024-12-10 04:15:27

单例模式通常被认为是不好的实践,因此经验证据(您“看到最多的”)在这种情况下没有什么价值。

第一个版本使用动态分配,而第二个版本使用静态分配。也就是说,第二次分配不能失败,而第一次分配可能会抛出异常。

这两个版本都有优点和缺点,但通常您应该尝试完全不需要单例的不同设计。

The singleton patterns is commonly considered Bad Practice, so empirical evidence (what you "see most") is of little value in this case.

The first version uses dynamic allocation, while the second one uses static allocation. That is, the second allocation cannot fail, while the first one could possibly throw an exception.

There are pros and cons to both versions, but generally you should try for a different design that doesn't require singletons at all.

你如我软肋 2024-12-10 04:15:27

第一个也是“惰性的”——只有在需要时才会创建它。如果您的 Singleton 很昂贵,这可能就是您想要的。

如果您的 Singleton 很便宜并且您可以处理未定义的静态初始化顺序(并且您在 main() 之前不使用它),那么您不妨选择第二个解决方案。

The first one is also "lazy" - it will be created only if and when it is needed. If your Singleton is expensive, this is probably what you want.

If your Singleton is cheap and you can deal with undefined order of static initialization (and you don't use it before main()), you might as well go for the second solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文