`
wx1569567608
  • 浏览: 70127 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

动态库中单例一记

 
阅读更多


20093729_7ubV.png

20093729_amtv.png



1       一个简单的Singleton

我们先来看一个简单的单件类的定义:

#include<iostream>

class Singleton

{

public:

static Singleton& GetSingleton()

{

    static Singleton singleton;

    return singleton;

}

void Print()

{

    std::cout<<"Singleton Print\n";

}

private:

Singleton::Singleton()

{

    std::cout<<"singleton constructor\n";

}

};

这个类提供了一些的功能(函数Print), 并禁止我们创建这个类的对象(构造函数为private), 提供给我们一个静态函数接口来访问这个单件对象(GetSingleton),利用静态变量的特点实现了其单一性。但是, 这个类有问题吗?

2       问题所在

是的,上面这个简单的类的确存在问题,而且是一个很严重的问题,这个问题让Singleton类完全失去它存在的意义, 因为它不再唯一!

是的, 当我们只在一个模块中使用这个类时(比如说,一个exe,这个类是没有问题的。但是, 一个稍微复杂一点的软件, 为了开发的便捷,提高复用度,降低耦合性等原因,其难免会被分成好几个模块。那么假设讲我现在有两个模块,一个DLL(singleton.dll), 用来提供一些基础的功能, 一个EXE(test.exe),用来提供真正的软件逻辑。 我现在singleton.dll中封装了一个Print的函数间(用类Singleton实现)并暴露出来。

singleton.dll

void Print()

{

    Singleton::GetSingleton().Print();

}

并在test.exe中这样调用:

Test.exe

Singleton::GetSingleton().Print();

Print();

这个时候,我们会发现在调用Singleton::GetSingleton().Print()时会产生一个Singleton对象, 而在调用Print()时, 也会产生一个Singleton对象, 也就是说我们有了两个Singleton实例, singleton不再是singleton。那么, 为什么会这样呢。

static Singleton& GetSingleton()

{

    static Singleton singleton;

    return singleton;

}

这个函数应该只会在第一次调用时创建Singleton对象,无论如何, 不应该出现会创建两次, 调用两次构造函数的情况。对于静态变量特性理解没错(只在第一次经过时被初始化), 编译器也没问题(vc8.0),难道两次经过该静态变量是都是第一次? 那么,难道两次调用的GetSingleton函数并不是同一个函数?让我们逐一来看:

1) Singleton::GetSingleton().Print()

Test.exe中直接调用该函数,因为包含的头文件singleton.h有完整的实现, 在链接时会在Test.exe保存一份Singleton::GetSingleton()的实现代码。

将其标为Singleton::GetSingleton_1();

2) Print();

Print()函数是从singleton.dll中导出而来的,而Print()会调用Singleton::GetSingleton(), 在链接模块singleton.dll时,因为其包含的头文件有完整的实现, 这个DLL也会保存一份Singleton::GetSingleton()的执行代码。 我将它标为Singleton::GetSingleton_2(), 虽然我们包含的是同一个头文件,两个是相同的函数名字, 但是这个函数在两个不同的模块中都存有一份独立的实现。实际上, 他们已经成为两个不同的函数了。

看来,两个函数的确不是同一个函数。

3       如何解决

既然知道了原因,就会有相应的解决方法。既然我们知道有两份独立的代码分别存在于两个模块中, 那么我们要做的就是让它只有一份。最好的结果就是这个函数保存在dll中, 在Test.exe不再存有该函数的执行代码, 而是调用dll中的那个函数。现在结果很明显了:将Singleton.h编译链接singleton.dll并将外部需要使用的函数暴露出来。这样, 不管有多少模块使用到singleton, 我们始终执行singleton.dll中的代码。

如下:

SINGLETON_API static Singleton& GetSingleton()

{

     static Singleton singleton;

     return singleton;

}

注:

#ifdef SINGLETON_EXPORTS

#define SINGLETON_API __declspec(dllexport)

#else

#define SINGLETON_API __declspec(dllimport)

#endif

这样在test.exe中使用该函数时,就不会再产生一个副本了,从而保证了我们的应用程序只有一个singleton

转载于:https://my.oschina.net/u/158055/blog/694483

分享到:
评论

相关推荐

    singleton_crash:演示由多个动态库链接的静态库中的单例导致的崩溃

    静态库中的单例如果在多个动态库中被使用,每个动态库都会有自己的副本,这违反了单例模式的初衷——在整个应用程序中只有一个实例。 具体来说,问题可能出在以下几个方面: 1. **内存管理**:每个动态库都可能...

    动态库Demo

    2. 单例模式:当一个动态库只需要一个全局实例时,可以采用单例模式,确保在进程范围内只有一个实例存在。 3. 抽象工厂模式:在跨平台的动态库开发中,可以利用抽象工厂模式提供一个接口,用于创建相关或依赖的对象...

    单例实现源码singleton-C++

    在软件设计模式中,单例模式是一种常用的模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。在C++中实现单例模式有多种方法,每种方法都有其优缺点。以下是对"单例实现源码singleton-C++"的详细...

    Sqlite3 C++ 简单单例数据库操作类封装

    `sqlite3.dll`是SQLite3的动态链接库,`sqlite3.h`包含了SQLite3的API声明,`sqlite3.lib`是静态链接库文件,用于编译时链接SQLite3库。`sqlite3_test.txt`可能是一个测试文件,用于验证单例类的功能。 在`CSqlite3...

    javaweb项目+设计模式(单例模式,工厂模式,动态代理,适配器)

    在这个`CloudMusic`项目中,可以预见的是,单例模式可能被用来管理数据库连接,工厂模式用于根据需求创建不同的音乐播放器对象,动态代理可能用于实现用户行为的日志记录或权限控制,而适配器模式则可能用于集成第三...

    中间件实例,动态链接库实例及调用实例,静态态链接库实例及调用实例,单接口COM组件,多接口COM组件

    动态链接库是Windows操作系统中的一种共享库机制,它包含可由多个程序同时使用的代码和数据。在运行时,动态链接库被加载到进程的地址空间中,允许程序调用其中的函数或使用资源,而无需将所有代码都包含在每个应用...

    工程简单重构,封装动态链接库

    1. **创建项目**:在Visual Studio等开发环境中,选择“新建项目”,然后选择“动态库”模板。这将生成一个基础的DLL项目框架。 2. **编写函数接口**:DLL对外提供服务通常是通过导出函数实现的。在头文件中声明...

    单例模式

    单例模式是软件设计模式中的一种,它的主要思想是确保一个类只有一个实例,并提供一个全局访问点。在软件工程中,这种模式常用于控制资源的共享,比如数据库连接、线程池或者配置对象等,因为这些对象创建和销毁的...

    通过python实现单例模式(类变量).rar

    Python 作为一种动态类型的脚本语言,实现单例模式有多种方式,例如使用模块级别的变量、基类元类、装饰器等。在本次分享的压缩包文件中,代码采用的是类变量的方式来实现单例模式。这种实现方式的主要思路是将类的...

    使用qt的引导界面,包括xml,自定义控件,单例模式的使用

    在本文中,我们将深入探讨如何使用Qt框架创建一个引导界面,重点关注XML的使用、自定义控件的开发以及单例模式的应用。Qt是一个强大的跨平台应用程序开发框架,它提供了丰富的库和工具,使得开发者能够轻松地构建...

    php+mysql+jqury+ajax+mvc+单例模式事例

    单例模式通过控制类的实例化过程,保证在整个应用程序中只有一个实例存在。 结合以上知识点,"php+mysql+jqury+ajax+mvc+单例模式事例"是一个适合初学者的项目,它可能包含了一个简单的MVC框架,使用PHP处理后端...

    K7120模块VC程序包含DLL库.rar_K7120模块VC程序包含DLL库_USB动态库_USB转CAN模块

    3. **DLL动态库**:动态链接库(Dynamic Link Library, DLL)是Windows操作系统中的一种共享代码的机制。开发者可以创建DLL文件,其中包含可被多个程序同时使用的函数和资源。在本项目中,DLL库可能是用于处理USB-...

    单例、工厂、策略模式C++、qt

    例如,你可以使用单例模式管理Qt应用程序的全局设置,工厂模式用于动态创建和管理不同类型的设备(如device文件中可能包含的各种硬件设备),而策略模式则可用于处理设备的多种工作模式或策略。 通过这样的设计,你...

    JSP+Servlet+达梦数据库+JDBC单例 web项目demo.zip

    JSP(Java Server Pages)和Servlet是Java EE(Java Platform, Enterprise Edition)技术的一部分,它们主要用于开发动态网站。JSP是一种基于Java的服务器端技术,允许开发者将Java代码嵌入到HTML页面中。而Servlet...

    动态链接库封装源码(第一条链接源码)

    - 创建DLL项目:使用Qt Creator新建一个Qt库项目,选择动态库类型。 - 定义接口:创建公共头文件,声明对外提供的函数和类。 - 实现功能:在源文件中实现这些函数和类。 - 封装:确保库函数不直接依赖于Qt私有...

    UE4插件调用第三方库

    将第三方库的源代码或编译好的库文件(如静态库或动态库)添加到插件的`Source`目录下。如果库是C++代码,可以将其放在`Private`目录,如果只需要链接库文件,可以放在`ThirdParty`目录下。 3. **配置第三方库** ...

    VC++动态链接库详解

    2. **设置属性**:在项目属性中,确保“配置类型”设置为“动态库 (.dll)”,并根据需要配置其他编译和链接选项。 3. **编写代码**:在头文件中声明接口,即需要暴露给其他程序调用的函数和类。在源文件中实现这些...

    Tablayout 单例和混合使用

    首先,`TabLayout`是Android设计支持库中的一个组件,用于创建标签页式的界面,通常与`ViewPager`配合使用,实现滑动切换不同页面的效果。在`MainActivity`中,我们可能会设置`TabLayout`与`ViewPager`的关联,通过`...

    NodeJS设计模式总结【单例模式,适配器模式,装饰模式,观察者模式】

    NodeJS设计模式是一种在开发过程中遵循的一套最佳实践,它帮助开发者组织代码,提高代码的可复用性和可维护性。以下是对四种设计模式——单例模式、适配器模式、装饰模式和观察者模式的详细说明。 1. **单例模式**...

    ios一些案例的demo(单例模式,倒影,雪花,动画组,图片水印,画板,画饼图。。。)

    1. **单例模式**:单例模式是一种设计模式,保证一个类只有一个实例,并提供一个全局访问点。在iOS中,常用于配置管理、网络请求等场景。例如,网络请求管理器通常被设计为单例,确保在整个应用程序中只有一份实例,...

Global site tag (gtag.js) - Google Analytics