4

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

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

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

4

5 回答 5

7

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

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

有关详细信息,请参阅静态变量初始化顺序

于 2012-12-11T01:57:27.193 回答
1

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

于 2012-12-11T01:58:17.670 回答
1

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

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

所以这样做并不聪明。

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

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

于 2012-12-11T02:14:00.417 回答
1

回答您的问题:您建议的情况更像是 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
}

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

于 2012-12-11T02:31:56.723 回答
0

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

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

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