3

我在尝试创建单例时想出了这个。示例:(我正在尝试制作MySelf一个线程安全且不使用双重检查锁定的单例)

class MySelf
{
private:
    string Name;
    int Age;

    MySelf()
    {
        Name = "Deamonpog";
        Age = 24;
        cout << "Constructing MySelf : " << Name << endl;
    };

    friend class MySingleton;

public:
    ~MySelf(){ cout << "Destructing MySelf : " << Name << endl; };

    int MyAge() const
    {
        return Age;
    }
};

class MySingleton
{
private:
    static MySelf mself;
public:
    static MySelf * GetInstance()
    {
        return &mself;
    }
};

MySelf MySingleton::mself;

现在我可以轻松地使用它,

cout << "I am " << MySingleton::GetInstance()->MyAge() << endl;

我不想要延迟初始化,因为我要创建的类将从头到尾都存在。但是这个线程安全吗?(据我所知,这似乎还可以)

如果这没问题,那么我应该使用这样的通用编程,

template <class T>
class GenericSingleton
{
private:
    static T _instance;

public:
    static T * GetInstance()
    {
        return &_instance;
    }
};

template <class T>
T GenericSingleton<T>::_instance;

所以我也可以将它与任何其他类一起使用。我只需要添加friend class GenericSingleton<MySelf>;到所需的 sigleton(例如添加到 MySelf 类)。

这种实现会引起麻烦吗?我实际上正在创建一个库。一些单例将被导出,而有些则不会。另外,如果这不是一个库,而只是另一个应用程序怎么办?

- 编辑 -

所以现在我必须这样做(因为我使用的是仍然不支持 C++11 的 VC++),

static MySelf & GetInstance()
{
    WaitForMutex(mymutex); // some function from the threading library
    if( NULL == _instance )
    {
         _instance = new MySelf();
    }
    ReleaseMutex(mymutex); // release function of the same library
    Return _instance;
}

并告诉用户使用该功能一次,然后将其缓存以供使用。(或者我也可以将函数重命名为Initialize()并创建另一种方法来仅返回引用而无需任何锁定或创建。)那么mymutex应该在哪里?它应该在哪里初始化?

4

2 回答 2

6

,但这不是主要问题。

全局对象(如static)的初始化跨翻译单元是无序的;这意味着如果在创建我调用的一个全局变量期间,MySingleton::GetInstance()我最终可能会得到一个指向未初始化内存的指针。

请参阅初始化顺序惨败

最重要的是,如果我要在这个初始化阶段启动第二个线程,它可以访问部分初始化的对象。

一般来说,建议使用 Meyer 的 Singleton:

MySelf& MySelf::Instance() { static MySelf S; return S; }

它以两种方式回避了初始化顺序的失败:

  • 保证Instance()返回时对象被初始化
  • 从 C++11 开始,编译器需要对初始化代码进行检测,以便在初始化期间检测到重入访问(gcc 在 C++03 中已经完成)

此外,从 C++11 开始,这需要是线程安全的:也就是说,如果Instance()在构造对象时另一个线程调用,它将耐心等待直到构造结束,然后返回与所有其他对象相同的实例线程(gcc 已经在 C++03 中做了)。

注意:使用无关的类只是更多的输入而没有附加值,放弃它。

于 2012-11-29T09:48:42.937 回答
5

这是更简单的实现:

template <class T>
class GenericSingleton
{
public:
    static T& GetInstance()
    {
        static T _instance;
        return _instance;
    }
};

它在C++11中也是线程安全的,因为静态变量在任何线程之前创建。

于 2012-11-29T09:38:01.760 回答