【问题标题】:Can everything in a singleton be static?单例中的所有内容都可以是静态的吗?
【发布时间】:2012-12-11 01:54:31
【问题描述】:

在 C++ 中,单例中的所有成员可以是静态的,还是尽可能多的?我的想法是,无论如何,全球只有一个实例。

在搜索时,我确实发现了很多关于 C# 中静态类的讨论,但对此并不熟悉。也想了解一下。

无论你有什么想法,请发表评论。

【问题讨论】:

    标签: c++ static singleton


    【解决方案1】:

    对于静态单例,您无法控制何时分配和构造单例。这使您受制于静态变量的 c++ 构造规则顺序,因此如果您在构造另一个静态变量的过程中碰巧调用了这个单一变量,那么这个单一变量可能还不存在。

    如果您不打算从另一个静态变量的构造函数中调用单例,并且不希望出于任何原因延迟构造,则可以为单例使用静态变量。

    请参阅Static variables initialisation order 了解更多信息。

    【讨论】:

    • 这不是真的。这取决于你如何构造单例。 new 创建的单例有明确的起点。这方面的例子可以在 Ogre3D SDK 中看到。
    • 我从未见过不是静态变量的 C++ 单例。 T* 或本地静态 T(Meyers 的单身人士)。相反,问题是关于单例的 数据成员 是否可以合理地是静态的,并且对于这些成员(但不是单例本身),上述描述成立。
    【解决方案2】:

    你可能知道,单例模式包含一个静态方法 Instance,当且仅当它存在时,它将创建实例并返回该实例。没有理由单例的其他或所有方法不能是静态的。但是,鉴于该类只有一个实例,我不确定将其他所有内容设为静态是否有意义。这有意义吗?

    【讨论】:

    • 并非总是如此。阅读我对@Troy 答案的评论。
    • 我不确定你的意思。我所说的单例模式是由 new 以静态方法创建的。
    • 这在设计上很糟糕。那么谁删除指针呢?无论哪种方式,我都在评论您的陈述“您可能知道,包含一个静态方法实例,该实例仅当它存在时才会创建实例......”。我指出这不是唯一的方法。您可以在静态方法的外部创建单例。
    • 我明白了,谢谢。我见过的单例(我不惜一切代价避免它们)只创建一次,并且在程序的生命周期内永远不会被删除。无论如何,单身人士应该是最后的手段。
    【解决方案3】:

    单例的大部分意义在于对它的创建时间进行一些控制。

    对于静态数据成员,您将失去对这些成员的控制权。

    所以这样做并不聪明。

    也就是说,单例通常是 Evil™,存在许多与纯全局变量相同的问题,包括倾向于充当无法控制的通信中心,将各种不可预测的影响从不可预测的地方传播到其他不可预测且很大程度上未知的地方地点,在不可预知的时间。

    因此,认真思考是个好主意:单身真的是答案吗?或者,在手头的情况下,它是否只是一种解决问题的方法?解决?

    【讨论】:

    • @serial downvoter:你不觉得你做得过火了。
    【解决方案4】:

    回答您的问题:您建议的情况更像是 C# 中的“静态类”,而 C++ 没有“静态类”的概念。

    通常在 C++ 单例类中,唯一的静态数据成员是单例实例本身。这可以是一个指向单例类的指针,也可以是一个简单的实例。

    有两种方法可以在单例实例不作为指针的情况下创建单例类。

    1)

    class MySingletonClass
    {
    public:
        static MySingletonClass& getInstance()
        {
            static MySingletonClass instance;
            return instance;
        }
    
        // non-static functions
    
    private:
        // non-static data-members
    };
    

    2)

    class MySingletonClass
    {
    public:
        static MySingletonClass& getInstance()
        {
            return sInstance;
        }
    
        // non-static functions
    
    private:
        static MySingletonClass sInstance;
        // non-static data-members
    };
    // In CPP file
    MySingletonClass MySingletonClass::sInstance;
    

    这个实现不是线程安全的,不能预测它何时被构造或何时被销毁。如果此实例依赖于另一个单例来销毁自身,则在退出应用程序时可能会导致无法识别的错误。

    带有指针的那个看起来像这样:

    class MySingletonClass
    {
    public:
        static MySingletonClass& getInstance()
        {
            return *sInstance;
        }
        static MySingletonClass* getInstancePointer()
        {
            return sInstance;
        }
    
        MySingletonClass()
        {
            if (sInstance) {
                throw std::runtime_error("An instance of this class already exists");
            }
            sInstance = this;
        }
    
        // non-static functions
    
    private:
        static MySingletonClass* sInstance;
        // non-static data-members
    };
    

    这种单例类的初始化通常会在应用程序初始化期间发生:

    void MyApp::init()
    {
        // Some stuff to be initalized before MySingletonClass gets initialized.
        MySingletonClass* mySingleton = new MySingletonClass(); // Initalization is determined.
        // Rest of initialization
    }
    
    void MyApp::update()
    {
        // Stuff to update before MySingletonClass
        MySingletonClass::getInstance().update(); // <-- that's how you access non-static functions.
        // Stuff to update after MySingletonClass has been updated.
    }
    
    void MyApp::destroy()
    {
        // Destroy stuff created after singleton creation
        delete MySingletonClass::getInstancePointer();
        // Destroy stuff created before singleton creation
    }
    

    虽然在这个场景中控制了单例的初始化和销毁​​,但是单例在多线程应用程序中并不能很好地发挥作用。我希望这能消除您的疑虑。

    【讨论】:

      【解决方案5】:

      简短的回答:是的!当然! C++ 很灵活,几乎一切皆有可能(尤其是这么简单的事情)。

      详细答案取决于您的用例。

      • 其他静态/全局变量如何取决于您的签名
      • 第一次访问单例的时间(可能在 main 之前?)
      • 您必须考虑的许多其他事情(其中大部分与您的单身人士与其他实体的交互有关)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多