跨DLL单例模板

文章提供了一个C++实现的Singleton模式,特点是多线程安全、适用于动态库和可执行文件,并采用懒加载构造。通过getSharedInstance函数和BaseSingleton模板类,确保了单例对象的唯一性和线程安全性。
摘要由CSDN通过智能技术生成

BaseSingleton.h

#ifndef BASESINGLETON_H
#define BASESINGLETON_H

#include <typeindex>
#include "base_export.h"
#include <mutex>
//class BASE_EXPORT BaseObject
// Singleton mode for cpp
//
// Features --
//   1. Works for both dynamical library and executable.
//   2. Multithread safe
//   3. Lazy consturction

BASE_EXPORT void getSharedInstance(const std::type_index &typeIndex,
                                     void *(*getStaticInstance)(),
                                     void *&instance);


template<typename T>
class BaseSingleton
{
public:
    static T* Instance()
    {
        static void* instance = nullptr;
        if (instance == nullptr)
        {
            getSharedInstance(typeid(T), &getStaticInstance, instance);
        }
        return reinterpret_cast<T *>(instance);
    }
private:
    static void* getStaticInstance()
    {
        static T t;
        return reinterpret_cast<void *>(&reinterpret_cast<char &>(t));
    }
};

template<typename T>
inline T* singleton()
{
    return BaseSingleton<T>::Instance();
}
#define Singleton(T) BaseSingleton<T>::Instance()

#endif // BASESINGLETON_H

BaseSingleton.cpp

#include "BaseSingleton.h"
#include <typeinfo>
#include <unordered_map>
#include <mutex>
#include <memory>
#include <iostream>
namespace {
struct SingleTonHolder
{
    void* object_;
    std::shared_ptr<std::mutex> mutex_;
};
}

static std::mutex& getSingleTonMutex()
{
    // Global mutex
    // s_singleTonMutex is not 100% safety for multithread
    // but if there's any singleton object used before thread, it's safe enough.
    static std::mutex s_singleTonMutex;
    return s_singleTonMutex;
}

static SingleTonHolder* getSingleTonType(const std::type_index &typeIndex)
{
    static std::unordered_map<std::type_index, SingleTonHolder> s_singleObjects;

    // Check the old value
    std::unordered_map<std::type_index, SingleTonHolder>::iterator itr = s_singleObjects.find(typeIndex);
    if (itr != s_singleObjects.end())
    {
//        std::cout<<__FUNCTION__<<__LINE__<<"======find====="<<typeIndex.name()<<std::endl;
        return &itr->second;
    }
    // Create new one if no old value
    std::pair<std::type_index, SingleTonHolder> singleHolder( typeIndex, SingleTonHolder() );
    itr = s_singleObjects.insert(singleHolder).first;
    SingleTonHolder& singleTonHolder = itr->second;
    singleTonHolder.object_ = nullptr;
    singleTonHolder.mutex_ = std::shared_ptr<std::mutex>(new std::mutex());

    return &singleTonHolder;
}

void getSharedInstance(const std::type_index &typeIndex,
                       void *(*getStaticInstance)(),
                       void *&instance)
{
    // Get the single instance
    SingleTonHolder* singleTonHolder = nullptr;
    {
        // Locks and get the global mutex
        std::lock_guard<std::mutex> myLock(getSingleTonMutex());
        if (instance != nullptr)
        {
            return;
        }
        singleTonHolder = getSingleTonType(typeIndex);
    }

    // Create single instance
    {
        // Locks class T and make sure to call construction only once
        std::lock_guard<std::mutex> myLock(*singleTonHolder->mutex_);
        if (singleTonHolder->object_ == nullptr)
        {
            // construct the instance with static funciton
            singleTonHolder->object_ = (*getStaticInstance)();
        }
    }

    // Save single instance object
    {
        std::lock_guard<std::mutex> myLock(getSingleTonMutex());
        instance = singleTonHolder->object_;
    }
}

base_export.h

#ifndef BASE_EXPORT_H
#define BASE_EXPORT_H

#ifdef BASE_STATIC_DEFINE
#  define BASE_EXPORT
#  define BASE_NO_EXPORT
#else
#  ifndef BASE_EXPORT
#    ifdef Base_EXPORTS
        /* We are building this library */
#      define BASE_EXPORT __declspec(dllexport)
#    else
        /* We are using this library */
#      define BASE_EXPORT __declspec(dllimport)
#    endif
#  endif

#  ifndef BASE_NO_EXPORT
#    define BASE_NO_EXPORT 
#  endif
#endif

#ifndef BASE_DEPRECATED
#  define BASE_DEPRECATED __declspec(deprecated)
#endif

#ifndef BASE_DEPRECATED_EXPORT
#  define BASE_DEPRECATED_EXPORT BASE_EXPORT BASE_DEPRECATED
#endif

#ifndef BASE_DEPRECATED_NO_EXPORT
#  define BASE_DEPRECATED_NO_EXPORT BASE_NO_EXPORT BASE_DEPRECATED
#endif

#if 0 /* DEFINE_NO_DEPRECATED */
#  ifndef BASE_NO_DEPRECATED
#    define BASE_NO_DEPRECATED
#  endif
#endif

#endif /* BASE_EXPORT_H */
单例模式是一种设计模式,用于确保一个类只有一个实例,并提供全局访问点。在C++中,可以通过以下步骤实现单例模式: 1. 创建一个类,将其构造函数、拷贝构造函数和赋值运算符声明为私有,以防止外部直接创建或复制实例。 2. 在类中定义一个静态成员变量,用于保存类的唯一实例。 3. 提供一个公共的静态成员函数,用于获取该唯一实例。在此函数中,检查静态成员变量是否已经被初始化,如果没有,则创建一个新实例并返回。 4. 使用单例类时,只需调用公共的静态成员函数即可获得类的唯一实例。 关于DLL(动态链接库),在使用单例模式时需要注意以下几点: 1. 单例类的实例在DLL中是唯一的,即使在同一个进程中加载了多个相同的DLL,也只有一个实例。 2. 需要确保DLL中的单例实例在整个进程中是可见且可访问的。可以将单例实例声明为导出函数,并使用导出关键字(如`__declspec(dllexport)`)导出它。 3. 在使用单例实例时,需要通过导入关键字(如`__declspec(dllimport)`)导入DLL中的单例实例。 需要注意的是,单例模式并不是线程安全的。在多线程环境下,可能会导致多个线程同时创建实例,破坏单例的初衷。因此,在实现单例模式时,需要考虑线程安全性,可以使用互斥锁或双重检查锁定等机制来保证线程安全。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值