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
相关推荐
singleton_crash 演示由多个动态库链接的静态库中的单例导致的崩溃
实现了单例模型。 vs2015的工程
中间件实例,动态链接库实例及调用实例,静态态链接库实例及调用实例,单接口COM组件,多接口COM组件,不同的创建实例及调用实例!
工程简单重构,封装动态链接库,讲述一下动态链接库是怎么搭建起来和使用的
1、Qt界面加载网络摄像头,并实时...4、本人使用Qt5.10.0、vs2015、opencv3.4.3,必须在运行根目录添加opencv动态库或将此库添加环境变量 5、里面涉及到一些单例模式、类静态成员的用法,后期再整理,供大家共同成长
小白提升:VS2019开发简单的C/C++动态链接库并在解决方案中进行调用 一、 vs2019简单动态链接库的开发 1.VS2019新建立一个空项目(DLL1) VS有提供dll项目的模板,可是对于我来说反而搞不懂模板中的文档,于是建立空白...
17.3 在Python中使用C++库 598 17.4 调用Windows DLL的函数 601 17.5 在多线程环境中使用SWIG生成的模块 603 17.6 用PySequence_Fast将Python序列转为 C数组 604 17.7 用迭代器逐个访问Python序列的元素 608 ...
因此,此存储库提供了一种动态确定过滤器的简便方法,并且可以与Spring MVC / Spring Boot很好地集成。 对于Spring Boot: 要求Java 8 支持的Spring IO平台: 下载要使用Maven添加依赖项,请使用以下命令: ...
讨论各种能够影响良好API设计的C++语言特性,如良好构造函数和操作符风格、命名空间、指针和引用参数的比较、友元的使用以及如何在动态库中导出符号。 第7章:性能。分析API的性能问题并说明如何使用C++构建高性能的...
实例128 获取数组中最后一个元素 158 实例129 去除数组中的重复元素 158 实例130 字符串与数组的转换 159 实例131 对数组元素进行随机排序 160 实例132 随机抽取数组中元素 161 实例133 二维数组的输出 162 实例134 ...
学习C++,学习windows/linux编程,学习网络编程,学习reactor模型,自己实现一遍练手; 包含(以下实现是Windows/Linux平台通用的,美名其曰跨平台) 基本工具库: 日志工具(日志优先级、同步日志、异步日志、带...
实例128 获取数组中最后一个元素 158 实例129 去除数组中的重复元素 158 实例130 字符串与数组的转换 159 实例131 对数组元素进行随机排序 160 实例132 随机抽取数组中元素 161 实例133 二维数组的输出 162 实例134 ...
SMART系统是一个新型智能在线考试信息管理系统,该系统主要实现了学生在线考试与...基于WEB的在线考试系统的主要好处是一方面可以动态地管理各种考试信息,只要准备好足够大的题库,就可以按照要求自动生成各种试卷;
AndroidManifest.xml中需要注册权限和service.(读写文件的权限要在代码中动态申请,不要忘记这点了) <!-- 注册service --> 2, 开始/暂停/重启 下载任务。 开始 //先获得这个单例对象 mDownloadHelper...
3. 反射和字节码操作:学习使用Java的反射机制和字节码操作库,实现动态代理、代码生成和运行时修改类的功能。 4. 函数式编程:学习Java 8及更高版本引入的函数式编程特性,如Lambda表达式和Stream API,提升代码...
Struts1只是在第一次请求的时候创建一个action实例,以后每次相同的请求都直接从内存中去读取,它是单例模式,安全性较差。 Struts2是如何实现MVC模式的? 答:在Struts2里面是将每次页面的请求进行处理,然后将请求...
将牛郎织女分开(本应在一起,分开他们,形成两个接口),在他们之间搭建一个桥(动态的结合) 设计模式之 Flyweight(共享元) 提供 Java运行性能,降低小而大量重复的类的开销. C. 行为模式 设计模式之 Command(命令) ...
在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...
15.4.8 一个完整的查看表中各列属性 15.4.8 的实例 258 15.5 常见问题与解决方案 259 15.6 小结 261 第16章 数据库中的程序逻辑 262 16.1 数据库程序逻辑与PHP程序逻辑的分体 16.1 设计原则 262 16.2 数据库中的程序...