学习AA大神c++设计新思维笔记:0607单件与灵针

单件

台湾人的,实作实现的意思.
很复杂的.
包括如何分配,如何消灭,多线程安全,消灭后操作.
静态函数/成员变量的缺点:不能为虚函数,外界很难改变行为.并且很难初化/清理.

<型名 T,<>类 创建策略=用新创建,<>类 生命期策略=默认生命期,<,>类 线程模型=洛基默认线程无对象级,
        类 互斥锁策略=洛基默认互斥锁
    >
    类 单件持有者{:

        又 T 对象类型;
        静 T&实例();:
        静 空 造实例();
        静 空 洛基限定c调用传统 消灭单件();
        
        单件持有者();
        又 型名 线程模型<T*,互斥锁策略>::易失类型 针实例类型;
        静 针实例类型 p实例_;
        静 极 消灭_;
    };
//这样实例化.
    {(!p实例_){造实例();}*p实例_;//静态初化.
    }//传回引用较安全,避免被`删`.

拷贝/复制构造声明为私/删.禁用.析构函数声明为.用消灭函数来消灭.
消灭时或者利用局部静态变量.要区别执行期初化编译期常量初化(运行前就完成赋值).利用的是退出时().c运行时程序结束时运行.
单件模式特征:易于表达/理解,但难以实现.
局部静态单件,不一定正确.如键盘,显示,日志.
键盘成功,显示失败,则日志跟随失败.则是死引用.因为日志也是单件.此时键盘再失败,则无法记录.因为日志已被消灭了.希望日志无论何时创建,但得在(键盘,显示)之后消灭.一个函数一个职责.现在要增加检测死引用,负责处理错误.增加一个已消灭变量.如果寿命更长对象取这个单件,则到达死引用时,并抛异常.
进一步,不死鸟来了.检测死引用复活.因为静态变量内存在整个程序周期都存在.在原地复活.新(针)单件.然后在退出时(注册消灭)
退出时修复.修复退出时问题.要定义#修复退出时.
不然,要出问题.
死引用.带寿命的单件.不死鸟,如有状态,则可能未保存状态.
生命期控制.现在的rust就有.置寿命,感觉就是自己当析构管家,管理析构顺序,只针对用分配的对象.
或者进行依赖管理.但也麻烦,会产生循环依赖.
寿命法则:A依赖B,则A比B短命.所以不要依赖.
带寿命单件,用类似优先队,但寿命值相同时,先进后出.
多线程更麻烦.双检测是错误的解法.锁很贵,最后可能得靠原子.

    空 单件持有者<T,创建策略,
        生命期策略,线程模型,互斥锁策略>::造实例()
    {
        型名 线程模型<单件持有者,互斥锁策略>::锁 警卫;
        ()警卫;(!p实例_)
        {(消灭_)
            {
                消灭_=;
                生命期策略<T>::死引用时();
            }//死引用时
            p实例_=创建策略<T>::创建();
            生命期策略<T>::计划析构(p实例_,
                &消灭单件);
        }
    }

灵针

现在已有独针,共针,弱针.具有两个操作->*操作.灵针具有值语义(即可以复制),而指针没有.
移动,共享(引用计数),总是复制指针,
拥有权与构造/复制/析构关系很大.
不要写死代码.降低通用性.如处理非标__near,__far,__huge时.如果有别人的灵针想对其升级时,将这个灵针包装在自己的灵针中,而不是继承他.
当调用->时,类型非内置类型,编译器不断->直到达到内置指针,再访问成员.因而灵针可以不传指针,而传有->方法的对象
前调用,后调用,假定按值从->操作返回一个指针对象,然后:
1,构造指针对象.
2,调用指针对象->,返回被指对象指针.
3,访问被指对象的->,执行实际动作.
4,析构指针对象.
在多线程及访问资源时有用,叫锁定函数调用,可在构造函数锁定资源,析构函数中解除锁定.
句柄防止用户直接操作资源.是隐藏表格的指针索引此时,提供->/*操作没意义.
因而,提出被指类型,存储类型,引用类型三种存储类型作为一种策略.灵针不适合用成员函数.因为会混淆灵针/被指对象的调用.
打印机也有获取/释放.光靠->/.来区别是不现实的.因而灵针只使用非成员函数,通过来解决.
灵针需要保留,构造,析构,->,=,*,函数,其余由命名非成员函数提供.
拥有权管理最重要.如移动,共享.
一种是,只管复制,比按值传递多的好处就是多态.深复制,用虚复制.具体复制时,返回子对象的基针,靠策略.
一是写时复制.但这个写时复制无法区分被指对象的常与非常成员函数调用.灵针太低级,写时复制很高级了.不过,实现写时复制时,可以用灵针.
引用计数,最普遍,最有效.这些都是小对象,最好用小对象分配器不然,分配太慢,如果通过间接层,则访问时又太慢.最好将计数通过被指对象保存起来.这是侵入式计数.非侵入式,最好也用小对象分配器.
还有引用链,双向引用链,插入,删除,空检测都是常数时间.引用链空间花费少,时间多.一般不用.
引用计数还有个问题,就是循环引用,这就是弱针上场时.
移动指针.转移所有权.还可以重载&操作符.取址.但不好.暴露了地址,放弃了自动管理.且不能使用stl了.因为多数代码假定用&返回T*.还可以隐式转为原始指针,可以通过显式转换使用.如.取()得到原始指针.
采取完整可靠操作,重载每个操作符.
还有,就是灵针<基>灵针<继>之间的转换.重载==!=为相应的模板类.

<型名 T1,<>类 操作1,类 CP1,<>类 KP1,<>类 SP1,<>类 CNP1>
        极 符号==(常 灵巧针<T1,操作1,CP1,KP1,SP1,CNP1>&右边){中 取实现(*)==取实现(右边);}

由用户来实现符号<以达到排序功能.借助标::较小可以实现.同一程序,可能需要高安/低速高速/低安.
检测分初化检测/提前检测.如不能为空针,但有时空针又有用.解引用时要检查,检查一次后,以后就不检查了.安全/高效.再一个是错误报告/错误策略,
双常性,指针的常,被指.
数组.如果灵针<数组>,则需要记得删[],此数组非现在数组.
多线程.被指对象锁定,加个间接层,构造函数中加个锁.借助->不断的->.访问后就析构间接层,释放锁了.
双链结构,都得加锁.将多线程加入所有者策略中.
类级锁定锁定某个类的所有对象.对象级锁定,只锁定对象相关操作.前者慢,占用内存少.后者快,占用内存多.多线程安全的引用计数,需要原子操作,多线程的引用链接则需要.原子操作相对来说,要便宜一点.
每一个可变点转为策略.
组合起来:存储,所有者,转换,检查策略.
把一个策略当作大函数,则什么都明白了.策略类直接作为模板的参数.一般,最常定制的策略放在最前.所有策略要具值语义:(复制构造/赋值)函数.

你可能感兴趣的:(笔记)