2021-09-29

本文介绍了C++11中通过使用局部静态变量实现线程安全的单例模式,这种方法避免了懒汉式单例模式在多线程环境下可能存在的线程不安全问题和内存泄漏。代码示例展示了如何在类中定义和使用单例,以及在main函数中创建多个线程调用单例方法,确保了单例的正确初始化和唯一性。
摘要由CSDN通过智能技术生成

c++ 单例模式的写法–笔记

大佬的更好的总结在:知乎文章

#ifndef SINGLE_TON_HH
#define SINGLE_TON_HH
#include <string>
namespace ThreadNamespace
{
    class SingleTon
    {
        SingleTon();
        ~SingleTon();
        SingleTon(const SingleTon&) = delete;
        SingleTon& operator=(const SingleTon&) = delete;
    public:
        std::string name;
        void myPrint(const std::string& n);
 
        //C++11规定了local static在多线程条件下的初始化行为,
        //要求编译器保证了内部静态变量的线程安全性。
        /*******************在C++11标准下*******************/
        //《Effective C++》提出了一种更优雅的单例模式实现,
        //使用函数内的 local static 对象。这样,只有当第一次访问getInstance()方法时才创建实例。
        //这种方法也被称为Meyers' Singleton
        static SingleTon& getInstance()
        {
            static SingleTon instance;
            return instance;
        }//c++11 之后最优雅的单例模式: 返回局部变量的引用.
    };

    // class SingleTon
    // {
    //     static SingleTon* inst;                              // 这种写法是线程不安全的
    //     SingleTon();
    //     ~SingleTon();
    //     SingleTon(const SingleTon&) = delete;
    //     SingleTon& operator=(const SingleTon&) = delete;
    // public:
    //     std::string name;
    //     void myPrint(const std::string& n);

    //     static SingleTon* getInstance()
    //     {
    //         if(inst != nullptr)
    //         {
    //             return inst;
    //         }
    //         return inst = new SingleTon();
    //     }
    // };

}
#endif
#include <iostream>
#include "SingleTon.hh"

using namespace std;

namespace ThreadNamespace
{
    // SingleTon* SingleTon::inst = nullptr;
    SingleTon::SingleTon()
        :name("")
    {
        std::cout<<"构造------------------------------------------------------------------------------>单例."<<std::endl;
    }
    SingleTon::~SingleTon()
    {
        std::cout<<"析构******************************************************************************单例!"<<std::endl;
    }
    void SingleTon::myPrint(const std::string& n)
    {
        std::cout<< (name.empty() ? n : name) <<std::endl;
    }
}

int main(void)
{
    std::vector<std::thread> pool;
    for(int i = 0; i<100; i++)
    {
        pool.emplace_back(
            std::thread(
                [](int k, const std::string& str){
                    std::cout<<"k is "<< k <<" ;"<< str <<" .thread_id: "<< std::this_thread::get_id() <<std::endl;
                    SingleTon::getInstance().name = "";
                    SingleTon::getInstance().myPrint("璃月");
                },
                i,
                "=="
            )
        );
    }
   
    //join()
    for(auto& iter : pool)
    {
        if(iter.joinable())
        {
            iter.join();
        }
    }
    return 0;
}

关于懒汉式,原生指针的写法是线程不安全且有内存泄漏的(至少在linux上是):

    class SingleTon
    {
        static SingleTon* inst;   // 这种写法是线程不安全的
        SingleTon();
        ~SingleTon();
        SingleTon(const SingleTon&) = delete;
        SingleTon& operator=(const SingleTon&) = delete;
    public:
        std::string name;
        void myPrint(const std::string& n);

        static SingleTon* getInstance()
        {
            if(inst != nullptr)
            {
                return inst;
            }
            return inst = new SingleTon();
        }
    };
    SingleTon* SingleTon::inst = nullptr;

    SingleTon::SingleTon()
        :name("")
    {
        std::cout<<"构造------------------------------------------------------------------------------>单例."<<std::endl;
    }

    SingleTon::~SingleTon()
    {
        std::cout<<"析构******************************************************************************单例!"<<std::endl;
    }

    void SingleTon::myPrint(const std::string& n)
    {
        std::cout<< (name.empty() ? n : name) <<std::endl;
    }
int main(void)
{
    std::vector<std::thread> pool;
    for(int i = 0; i<100; i++)
    {
        pool.emplace_back(
            std::thread(
                [](int k, const std::string& str){
                    std::cout<<"k is "<< k <<" ;"<< str <<" .thread_id: "<< std::this_thread::get_id() <<std::endl;
                    SingleTon::getInstance()->name = "";
                    SingleTon::getInstance()->myPrint("璃月");
                },
                i,
                "=="
            )
        );
    }

    //join()
    for(auto& iter : pool)
    {
        if(iter.joinable())
        {
            iter.join();
        }
    }
    return 0;
}

出错的结果:构造了两次

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值