创建型设计模式-单例

原文链接 单例模式及特殊类的设计

创建类-特殊场景

一个不能被拷贝的类

点击查看代码
class Test
{
public:
    Test(const Test &other) = delete;
    Test &operator(const Test &other) = delete;
}

一个不能被继承的类

final

一个只能在栈上创建的类

点击查看代码
class StackOnly
{
public:
    static StackOnly create() { return StackOnly(); }
    void* operator new(size_t size) = delete;
    void operator delete(void *p) = delete;

private:
    StackOnly();
}

一个只能在堆上创建的类

私有化构造函数,自实现创建方法
点击查看代码
class HeapOnly
{
public:
    static HeapOnly *create(){ return new HeadOnly(); }
private:
    HeapOnly() = default;
}
私有化析构函数

先解释为什么这个方法可行。一般来说:
C++是静态绑定的语言,在编译时期,所有的非虚函数调用都必须分析完成。则当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期(具体过程为: 通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数 )。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性(其实不光是析构函数,只要是非静态的函数,编译器都会进行检查)。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。 所以 析构函数私有化的类的设计可以保证只能用new命令在堆(heap)中创建对象。

点击查看代码
class HeapOnly
{
public:
    void destroy() { delete this; }
private:
    ~HeapOnly() = default;
}

一个只能实例化一个对象的类

单例模式 Singleton pattern


单例

饿汉式

程序启动时即创建。
优点:代码简洁;
缺点:内存始终被占用的缺陷,拖慢启动效率;单例应用于多个类时,启动时构建顺序随机;

点击查看代码
class Singleton
{
public:
    static Singleton& instance() {
        return *m_unique_obj;
    }

private:
    Singleton() = default;
    Singleton(const Singleton &other) = delete;
    Singleton& operator=(const Singleton &other) = delete;

private:
    static Singleton *m_unique_obj;
}
Singleton *Singleton::m_unique_obj = new Singleton();

另外需要知道的事

上述写法中唯一实例对象(全局静态变量)的构造为程序启动初始,而一个程序中所有的全局静态变量的构造和析构顺序是随机的,唯一的规律就是 构造和析构的顺序是相反的,但构造本身是没有规律可言的。

懒汉式

需要时才创建。
优点:节省内存,提升启动效率;按需进行构造;
缺点:代码较为复杂;
要注意多线程场景下的双重判断+锁来保证仅会唯一实例化一个对象。

点击查看代码
class Singleton
{
public:
    static Singleton& instance_1(){
        /* 锁+双重检验 */
        if (!pObject){
            mtx.lock();
            if (!pObject)
                pObject = new Singleton();
            mtx.unlock();
        }
        return *pObject;
    }
    static Singleton& instance_2(){
        /* 利用编译器对于静态局部变量的处理,保证了只有首次进入该函数块时才会进行static变量的构造 */
        static Singleton ins;
        return ins;
    }
    static void destroy(){
        mtx.lock();
        if (pObject){
            delete pObject;
            pObject = nullptr;
        }
        mtx.unlock();
    }
private:
    Singleton() = default;
    Singleton(const Singleton &other) = delete;
    Singleton &operator=(const Singleton &other) = delete;

private:
    static Singleton *pObject;
    static std::mutex mtx;
}

Singleton *Singleton::pObject = nullptr;
std::mutex Singleton::mtx;

两种实现方案,第二种会更为简洁,不易出错。

posted @ 2025-07-22 11:00  EndlessINF  阅读(8)  评论(0)    收藏  举报