c++: 单例模式(Singleton)的最优写法

目的

本例简介C++中单例模式的最优写法。

实现

基础写法

下面的代码是C++单例的基础写法,在静态函数Singleton::getInstance()中定义了Singleton的静态变量对象,并返回此对象的引用。
由于C++函数的静态变量唯一性,可以确保例子中s对象的唯一性,线程同步,以及静态对象间的依赖关系等问题。

#include <iostream>

class Singleton {
   
   
    public: static Singleton &getInstance() {
   
   
        static Singleton s;
        return s;
    }

    public: void test() {
   
   
        std::cout << "test" << std::endl;
    }
};

int main() {
   
   
    Singleton &s = Singleton::getInstance();
    s.test();
    return 0;
}

完整写法

如果对代码要求比较严格,可以把该关闭的函数都关掉,这取决与你:):

  • 构造函数私有化,使得外部无法创建Singleton对象。
  • 关闭拷贝构造函数,右值拷贝构造函数。
  • 关闭赋值运算符重载函数。
class Singleton {
   
   
    private: Singleton() {
   
    }
    Singleton(const Singleton &) = delete;
    Singleton(const Singleton &&) = delete;
    Singleton &operator=(const Singleton &) = delete;

    public: static Singleton &getInstance() {
   
   
        static Singleton s;
        return s;
    }

    public: void test() {
   
   
        std::cout << "test" << std::endl;
    }
};

对比

New

使用下面方法的也比较多,缺点是在无法保证getInstance()的线程安全性。如果工程比较大,会存在多个线程同时调用Singleton::getInstance()方法导致创建多实例的问题。

class Singleton {
   
   
    private: static Singleton *instance;

    public: static Singleton *getInstance() {
   
   
        if (NULL == instance)
            instance = new Singleton();

        return instance;
    }
};

Lock

所以可能会加一堆lock, 为了性能还写个double check, 比如下面这样,写起来比较麻烦,个人不太喜欢。

class Singleton {
   
   
    private: static Singleton *instance;

    public: static Singleton *getInstance() {
   
   
        if (NULL == instance) {
   
   
            // TODO LOCK
            if (NULL == instance)
                instance = new Singleton();
        }

        return instance;
    }
};

静态成员

如果把函数内的静态变量变成类的静态成员变量呢?简单的工程行,复杂的不行。因为如果静态类之间有依赖,可能会导致C++的一些未定义的行为。

  • 下例中的Singleton::instance 保存在程序全局的静态数据区,instance初始化的时机是在程序的main()函数执行前。
  • 假设有SingletonB::instance,与Singleton::instance类似定义,也是静态类成员变量。SingletonB::instance和Singleton::instance的初始化顺序是未定义的,得看编译器的心情。
  • 如果Singleton::instance 的初始化在SingletonB::instance之前,而Singleton的构造函数中恰好需要引用到SIngleonB::instance,就很可能会出现一些未定义的行为。
#include <iostream>

class Singleton {
   
   
    private: static Singleton instance;

    public: static Singleton &getInstance() {
   
   
        return instance;
    }
    
    public: void test() {
   
   
        std::cout << "test" << std::endl;
    }
};

Singleton Singleton::instance;

int main() {
   
   
    Singleton &s = Singleton::getInstance();
    s.test();
    return 0;
}

总结

  1. 如果项目小,建议上述单例中的简单写法就够了。
  2. 如果项目大,可以写全点儿。

引用

[1] Efficitive C++

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章