跳转至

2.1.2   单例与指针

单例与指针是我们编程开发中常常会用到的两种语法,主要的作用都是减少程序运行的开支,对于rbk这种大体量的程序尤为重要

指针

这个相信大一学过C++的同学都有极深的印象,就不多说了 - 简单来说,指针存储变量的地址,绝大多数情况下占用的内存较少 - 利用指针可以直接操纵内存地址,实现动态内存分配,从而可以完成和汇编语言类似的工作,这样可以提高程序的编译效率和执行速度,使程序更加简洁 - 另外还有: - 通过指针被调用函数可以向调用函数处返回除正常的返回值之外的其他数据,从而实现两者间的双向通信 - 指针还用于表示和实现各种复杂的数据结构,从而为编写出更加高质量的程序奠定基础

单例

这个课上并没有讲过,但在一个项目程序中是非常好用的

何为单例

  • 何为单例模式,在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:保证一个类只有一个实例,并提供一个访问它的全局访问点
  • 简单来说,就是让每一个类只实例化一次,避免反复创建和销毁带来的额外开销。另外,只有一个实例也可以保证其中变量值的来源,提高程序的稳定性

如何实现

  • 设计一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象
  • 落实到代码上,关键就是两点:
    • 在类中,要构造一个实例,就必须调用类的构造函数。如此,为了防止在外部调用类的构造函数而构造实例,需要将构造函数的访问权限标记为 protected 或 private
    • 需要提供要给全局访问点,就需要在类中定义一个静态函数,返回在类内部唯一构造的实例
  • 做到以上两点基本上就可以了。但如果项目中有多个线程,还要添加其他内容来维护线程安全,防止多个线程创建多个实例。关于这个的解决方法有很多,如加互斥锁、在主线程提前实例化等等,详细请见参考博客

代码示例

就举我们rbk项目里的单例为例,在 singleton.h 中定义

template <class SingletonClass >
class NormalSingleton{
public:
    static SingletonClass * Instance(){
        static SingletonClass* instance = 0;
        if( !instance ){
            instance = new SingletonClass;
        }
        return instance;
    }
    SingletonClass* operator ->() { return Instance(); }
    const SingletonClass* operator ->() const { return Instance(); }
private:
    NormalSingleton(){ }
    ~NormalSingleton(){ }
};
将一个类设为单例模式的方法也很简单,在原来的类预编译结束符 #endif 前添加如下语句,以CVisionModule为例,VisionModule是其单例模式的名称
typedef NormalSingleton<CVisionModule> VisionModule;
这样就可以在项目全局使用定义好的单例了,其中 f()、b 分别指类中 public 的函数和变量
VisionModule::Instance()->f();
VisionModule::Instance()->b;

指针 + 单例

我们的项目中为了最大化地节省运行资源,还有更高阶的用法,就是把单例和指针融合使用 - 从上文中的单例定义我们就可以看到,全局调用单例的函数 Instance() 返回的就是原来类的指针 - 所有单例的初始化都在主线程的最初完成,详见 Global.h,在 SSLStrategy.cpp 中调用

CVisionModule* vision;
vision = VisionModule::Instance();

参考博客