用阿里云服务器做盗版小说网站吗,莱芜网站,私域营销,怎么建立网站站点二十四、C的单例模式、跟踪内存分配的简单方法
1、C的单例模式 本小标题不是讨论C的语言特性#xff0c;而是一种设计模式#xff0c;用于确保一个类在任何情况下都只有一个实例#xff0c;并提供一个全局访问点来获取这个实例。即C的单例模式。这种模式常用于资源管理的单例模式、跟踪内存分配的简单方法
1、C的单例模式 本小标题不是讨论C的语言特性而是一种设计模式用于确保一个类在任何情况下都只有一个实例并提供一个全局访问点来获取这个实例。即C的单例模式。这种模式常用于资源管理如线程池、缓存、日志对象等以确保这些关键资源不会被过度使用同时节省内存。单例模式的核心在于类自身负责创建自己的唯一实例并提供一个静态方法来获取这个实例从而防止外部代码创建多个实例。
1关于单例模式的一点说明 单例模式说白了就是我只想有一个对象的单一实例。也就是只想有一个对象的单一的数据集比如一些专属它的变量和一些仅针对它的函数。当然这些函数也是仅仅针对这个对象的、特定的数据集的操作。 那么要实现单例模式至少有下面三种实现途径 一是用类来实现。像Java和C#它们天生就是面向对象语言所以它们强制你使用类。特别是java所有东西都必须是一个类你不能在类之外有代码如果你想要静态的功能你不需要实例化但你必须在你的类中创建静态成员。 二是可以用命名空间来实现。C不像Java和C#那么多规则限制C不对静态函数做这些规则限制所以C可以不需要写一个类可以在某个名称空间中写一些函数甚至在全局名称空间中它们不属于任何类的类型。其实说白了类名就是一种命名空间。用类来实现单例模式从根本上说就是将类用作命名空间来调用某些函数。 三是C可以有完全全局的变量或者可以有一个静态变量它被绑定到一个特定的翻译单元或者一个特定的CPP文件。也是可以实现单例模式的。
所以要实现单例模式并不一定非得用类来实现只是用类实现是最简单直观的。
2单例设计模式在哪里发挥作用呢 当我们想要拥有应用于某种全局数据集的功能而且我们只是想要重复使用时单例是非常有用的。比如一个随机数生成器我们只是希望能够查询它比如给我们一个随机数我们不需要实例化它遍历所有东西。因为我们只是想实例化它一次这样它就会生成随机数生成器的种子建立起它所需要的任何辅助的东西了。然后我们要调用一个函数基于我们初始化它的结果它会给我们一个随机数。 另一个很好的例子是渲染器渲染器通常是一个非常全局的东西。我们通常不会有一个渲染器的多个实例我们有一个渲染器我们向它提交所有这些渲染命令然后它会为我们渲染一些东西。如果我们将其分解到opengl的部分我们实际上通过渲染器调用opengl调用的东西本身就是一组全局函数。这根本不是和某种对象有关的东西它们只是C风格的函数没有类一点关系都没有。
3用类实现单例模式的几个关键点 发明类的初心就是重复使用创建任意个实例的但是现在我们只允许它只能有一个实例所以我们要通过下面几点来达到目的 一是私有构造函数防止外部通过new操作符创建多个实例因为new操作符的底层也是调用构造函数私有构造函数就无法调用。 二是使用静态变量存储类的唯一实例。 三是使用公共静态方法提供一个全局访问点来获取这个实例。
下面编写一个非常非常基本的、用类来实现单例的例子 这段代码通过将构造函数设为私有确保外部无法直接创建实例创建一个自身的实例并静态的、私有的存储然后通过一个公共的静态方法来获取那个实例。这些操作就让这个类成了一个单例类。
可见C中的类单例只是一种组织一堆全局变量和静态函数的方式这些静态函数有时可能对这些变量起作用有时也可能不对这些变量起作用。也就是在一个单一的名称空间下(类名)把这些全局变量和静态函数组织在一起。这就是C类单例的本质。
如果还是不是太理解的同学可以参考我之前写的博文 【C】类、静态static、枚举、重载、多态、继承、重写、虚函数、纯需函数、虚析构函数_静态与多态:重写、重载、模板-CSDN博客 中的static部分相信看完就明白了。
如果觉得上面的例子没有啥意义那我们利用单例类写一个随机数生成器 这个随机数生成器是我们在一开始就放入了随机数种子然后在整个程序中重用非常简单因为我们不需要一个随机数生成器有多个实例。上图单例仅仅是返回了一个静态值所以这个单例可以写成右边的静态函数。但是我们还是使用了类单例(左图)因为类单例之所以为类单例是因为它实际上还是一个类因此它可以支持所有的类特性比如类成员变量等。
如果说上面需要调用GetInstance再调用get_seed很麻烦我们可以这样改写
如果说上面的写法还是特别麻烦我们还可以这样写 此时左图的写法就清晰很多不需要像右图那样三步分散得到处都是可读性比较差。
结论单例的核心就是上面的GetInstance函数。单例的声明周期就是你的应用的生命周期。一旦我有了这个单例我可以写任何数量的非静态方法都可以通过GetInstance函数访问这些方法。
下面再简单展示一下使用命名空间实现的写法 虽然使用命名空间也可以实现但是失去了public、private这些类的功能。 2、跟踪内存分配的简单方法 如何跟踪内存的分配这个知识点其实前面都已经有过涉及这里就是进行一个小结。
知道你的程序什么时候分配内存特别是堆内存是非常有用的。尤其是在性能关键的代码中在堆上分配内存是很糟糕的做法。 如果你知道是哪行代码分配了内存你就可以针对性的优化你的程序使其运行得更快。此外如果你能看到内存被分配到哪里可以帮助你更好的理解你的代码的工作原理。所以本部分要编写代码跟踪应用程序内存的总体使用情况而不是依赖某些内存管理工具。 所以我们可以通过在operator new函数中插入一个断点就可以精确的追踪这些内存分配的来源。
下面写一个完整的new和delete
我们还可以维护一个allocation metrics,就可以确切知道有多少内存被使用有多少内存被分配有多少内存被释放等等 当然上面这个可能写得比较牵强anyway大体就是这么写的。
最后提一下VS内置的内存分配跟踪分析工具Valgrind,是一款用于内存调试、内存泄露检测以及性能分析的软件开发工具。自己写还是使用现有的工具这个你自己看着办吧。