使用友元类的单例实现(C++)

Dea*_*pog 3 c++ g++ visual-c++ c++03

我试图创建一个单身时想出了这个.示例:(我正在尝试创建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;
Run Code Online (Sandbox Code Playgroud)

现在我可以很容易地使用它,像

cout << "I am " << MySingleton::GetInstance()->MyAge() << endl;
Run Code Online (Sandbox Code Playgroud)

我不想要延迟初始化,因为我要创建的类将从头到尾.但这个线程安全吗?(据我所知,似乎没问题)

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

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

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

template <class T>
T GenericSingleton<T>::_instance;
Run Code Online (Sandbox Code Playgroud)

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

这种实施能否带来麻烦?我实际上正在创建一个库.有些单身人士要出口,有些则不出口.如果这不是一个库而只是另一个应用程序呢?

- 编辑 -

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

Mat*_* M. 6

,但这不是主要问题.

全局对象(例如static)的初始化在翻译单元之间是无序的; 这意味着如果在创建一个全局的过程中我正在调用,MySingleton::GetInstance()我最终会得到一个指向单元化内存的指针.

请参阅初始化订单Fiasco.

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

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

MySelf& MySelf::Instance() { static MySelf S; return S; }
Run Code Online (Sandbox Code Playgroud)

它以两种方式回避初始化顺序fiasco:

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

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

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


Den*_*lin 5

这是更简单的实现:

template <class T>
class GenericSingleton
{
public:
    static T& GetInstance()
    {
        static T _instance;
        return _instance;
    }
};
Run Code Online (Sandbox Code Playgroud)

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

  • 返回指针有什么意义?有没有*任何*机会,它可能是null? (3认同)