智能指针+句柄类 源自百科 [ 很有启发意义 ]

1、一般定义
  句柄类(智能指针smart point)是存储指向动态分配(堆)对象指针的类。除了能够在适当的时间自动删除指向的对象外,他们的工作机制很像C++的内置指针。智能指针在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象。他们也可以用于跟踪被多用户共享的动态分配对象。
  在C++中一个通用的技术是定义包装(cover)类或句柄(handle)类,也称智能指针。句柄类存储和管理基类指针。指针所指向对象的类型可以变化,它既可以指向基类类型对象又可以指向派生类型对象。用户通过句柄类访问继承层次的操作。因为句柄类使用指针执行操作,虚成员的行为将在运行时根据句柄实际绑定的对象类型而变化,即实现c++运行时动态绑定。故句柄用户可以获得动态行为但无需操心指针的管理。
2、理解实质
  句柄类实际上通过复制指向引用计数器类型的指针,来代替复制实际对象;从而使得复制对象变成复制指针,实现虚拟复制(即是用复制对象的地址代替复制对象本身),以提高内存效率和访问速度。在涉及到大型、复杂对象以及一些不能复制或是不易复制的对象的复制控制问题时,显得特别有用。
编辑本段句柄类涉及的技术
1、引入使用计数
  定义句柄类或智能指针的通用技术是采用一个使用计数(use count)。句柄类将一个计数器与类指向的对象相关联。使用计数跟踪该类有多少个指针共享同一对象。当使用计数为0时,就删除该类对象,否则再删除类对象时,只要引用计数不为0,就不删除实际的类对象,而是是引用计数减1,实现虚删除。
2、使用计数类
  为了便于理解,我们定义一个实际类(Point),一个引用计数器类(UPoint),一个句柄类(Handle),后面将有例子给以参考。
  实现使用计数有两种经典策略:一种是定义一个单独的具体的类用以封装使用计数和指向实际类的指针;
  另一种是定义一个单独的具体的类用以封装引用计数和类的对象成员。我们称这种类为计数器类(UPoint)。在计数器类中,所有成员均设置为private,避免外部访问,但是将句柄类Handle类声明为自己的友元,从而使句柄类能操纵引用计数器。
3、写时复制

  写时复制(copy on write)技术是解决如何保证要改动的那个引用计数器类UPoint对象不能同时被任何其他的句柄类(Handle类)所引用。通俗的来说,就是当实际对象Point被多个Handle类的指针共享时,如果需要通过指针改变实际对象Point,而其他的指针又需要保持原来的值时,这就有矛盾了。打个不恰当的比方来说,两个以上的人共有5W块钱,如果其中一个人想用这5W块钱去消费,那就必须通知其他人。否则在这个人消费了5块钱后,其他人还以为他们仍然有5W块钱,如果这儿时候,他们去买5W的东西,就会发现钱变少了或是没有了,此时他们就陷入债务的泥团。在C++中通过指针访问已经删除或是不存在的对象,将是非常危险的。有可能系统提示该行为未定义,也有可以内存非法访问,还有可能使系统崩溃。

启发例子如下 : [ 这个例子有个别地方我并不十分认同 ]

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define BUG cout << "here\n";
using namespace std;

// 句柄类中封装的实际对象类型;Point 
class Point {
public :
    Point() : xval(0), yval(0) {}
    Point(int x, int y) : xval(x), yval(y) {}
    int x() const { return xval; }
    int y() const { return yval; }
    Point& x(int xv) { xval = xv; return *this; }
    Point& y(int yv) { yval = yv; return *this; }

    ~Point() {
        cout << "~Point!" << endl; //测试时用于分析对象的析构过程;   
    }
private :
    int xval;
    int yval;
};
//引用类型计数器类;   
class UPoint { //所有的数据成员和函数成员均为:private类型 , 不允许普通用户改变
private :
    friend class Handle; //将句柄类声明为友元类,便于访问引用计数器;
    Point p; //声明一个Point实际对象的数据类型;实现数据隐藏;   
    int u;  //引用计数器;
    UPoint() : u(1) {} //当创建一个handle句柄对象时,将通过引用计数类自动创建一个Point的真实对象;//同时使计数器 U 自动为1
    UPoint(int x, int y) : p(x, y), u(1) {}
    UPoint (const Point & p0): p(p0), u(1) {}
    ~UPoint() {
        cout << "~UPoint!" << endl; //测试时用于分析对象的析构过程
    }
};

//句柄类实际上通过复制指向引用计数器类型的指针,来代替复制实际对象;从而使
//得复制对象变成复制指针,提高内存效率和访问速度;   
class Handle {
public: //句柄类的构造函数,主要通过复制句柄中指向基类的指针来实现对象复制的虚拟操作;   
//3个构造函数;
    Handle(): up(new UPoint) {}
    Handle(int x, int y): up(new UPoint(x,y)) {}
    Handle(const Point &p): up(new UPoint(p)) {}
    //复制函数;使引用计数自动加 1;
    Handle(const Handle &h ) : up(h.up) {++up->u;}

    //赋值函数;使赋值右侧对象的引用计数自动加 1;   
    Handle& operator= (const Handle &h) {
        ++h.up->u; //赋值右侧引用计数器加 1;   
        //如果up的引用计数器为1,就直接删除up所指向的对象;   
        //经验,任何改变实际引用计数器状态变化的操作都应该检查引用计算器   
        //是否为 0 ,为0就应该删除实际操作对象;   
        if(--up->u == 0) delete up;
        up = h.up;
        return *this; //返回修改指针up地址值的自身兑现引用;   
    }
    ~Handle() {     //如果 up 所指的对象 引用计数为 u 为最后一个,则应该删除对象
        if(--up->u == 0)
        delete up;
        cout << "~Handle!" << endl;
    }
    int x() const {
        return up->p.x();
    }
    Handle& x(int x0) {//采用句柄的值语义;     
    //更改up对象的值时,当引用计数不为 1时,则说明实际对象point 关联多个   
    //handle的 up指针,为了保持原来指针所指向对象的数据不被改变;此时   
    //需要 将该对象的引用计数 减 1, 然后重新定义一个新引用计数器类型  // 很棒!!!
        if (up->u != 1) { //将原对象的引用计数 减 1;再申请一个引用计数器对
    //采用写时复制技术解决更改Point对象时所带来的问题
            --up->u;
            up = new UPoint(up->p);
        }
        up->p.x(x0);
        return *this;
    }
    int y() const { return up->p.y(); }
    Handle& y(int y0) {
        if(up->u != 1) {
            --up->u;
            up = new UPoint(up->p);
        }
        up->p.y(y0);
        return *this;
    }
private :
    UPoint *up;
};
int main() {
    Handle h(23, 34), tmp(h); //定义句柄对象h,和tmp
    Handle val; //定义默认的句柄类对象
    //通过句柄类执行实际类Point 成员函数功能
    cout << "handle::h " << h.x() << '\t' << h.y() << endl;
    cout << "handle::tmp " << tmp.x() << '\t' << tmp.y() << endl;
    cout << "handle::val "<< val.x() << '\t' << val.y() << endl;
    BUG
    //关键的一步val = h;将涉及写时复制;因为h和tmp指针共享同一指针
    val = h.x(100); //改变句柄类 h 所指对象 point 对象x 的值后赋值给val句柄
    BUG
    cout << "handle::h " << h.x() << '\t' << h.y() << endl;
    cout << "handle::tmp " << tmp.x() << '\t' << tmp.y() << endl;
    cout << "handle::val "<< val.x() << '\t' << val.y() << endl;
    return 0;
}



源码来自:https://pan.quark.cn/s/a4b39357ea24 ### 操作指南:洗衣机使用方法详解#### 1. 启动与水量设定- **使用方法**:使用者必须首先按下洗衣设备上的“启动”按键,同时依据衣物数量设定相应的“水量选择”旋钮(高、中或低水量)。这一步骤是洗衣机运行程序的开端。- **运作机制**:一旦“启动”按键被触发,洗衣设备内部的控制系统便会启动,通过感应器识别水量选择旋钮的位置,进而确定所需的水量高度。- **技术执行**:在当代洗衣设备中,这一流程一般由微处理器掌管,借助电磁阀调控进水量,直至达到指定的高度。#### 2. 进水过程- **使用说明**:启动后,洗衣设备开始进水,直至达到所选的水位(高、中或低)。- **技术参数**:水量的监测通常采用浮子式水量控制器或压力感应器来实现。当水位达到预定值时,进水阀会自动关闭,停止进水。- **使用提醒**:务必确保水龙头已开启,并检查水管连接是否牢固,以防止漏水。#### 3. 清洗过程- **使用步骤**:2秒后,洗衣设备进入清洗环节。在此期间,滚筒会执行一系列正转和反转的动作: - 正转25秒 - 暂停3秒 - 反转25秒 - 再次暂停3秒- **重复次数**:这一系列动作将重复执行5次,总耗时为280秒。- **技术关键**:清洗环节通过电机驱动滚筒旋转,利用水流冲击力和洗衣液的化学效果,清除衣物上的污垢。#### 4. 排水与甩干- **使用步骤**:清洗结束后,洗衣设备会自动进行排水,将污水排出,然后进入甩干阶段,甩干时间为30秒。- **技术应用**:排水是通过泵将水抽出洗衣设备;甩干则是通过高速旋转滚筒,利用离心力去除衣物上的水分。- **使用提醒**:...
代码下载地址: https://pan.quark.cn/s/c289368a8f5c 在安卓应用开发领域,构建一个高效且用户友好的聊天系统是一项核心任务。 为了协助开发者们迅速达成这一目标,本文将分析几种常见的安卓聊天框架,并深入说明它们的功能特性、应用方法及主要优势。 1. **环信(Easemob)** 环信是一个专为移动应用打造的即时通讯软件开发套件,涵盖了文本、图片、语音、视频等多种消息形式。 通过整合环信SDK,开发者能够迅速构建自身的聊天平台。 环信支持消息内容的个性化定制,能够应对各种复杂的应用场景,并提供多样的API接口供开发者使用。 2. **融云(RongCloud)** 融云作为国内领先的IM云服务企业,提供了全面的聊天解决方案,包括一对一交流、多人群聊、聊天空间等。 融云的突出之处在于其稳定运行和高并发处理性能,以及功能完备的后台管理工具,便于开发者执行用户管理、消息发布等操作。 再者,融云支持多种消息格式,如位置信息、文件传输、表情符号等,显著增强了用户聊天体验。 3. **Firebase Cloud Messaging(FCM)** FCM由Google提供的云端消息传递服务,可达成安卓设备与服务器之间的即时数据交换。 虽然FCM主要应用于消息推送,但配合Firebase Realtime Database或Firestore数据库,开发者可以开发基础的聊天软件。 FCM的显著优势在于其全球性的推送网络,保障了消息能够及时且精确地传输至用户。 4. **JMessage(极光推送)** 极光推送是一款提供消息发布服务的软件开发工具包,同时具备基础的即时通讯能力。 除了常规的文字、图片信息外,极光推送还支持个性化消息,使得开发者能够实现更为复杂的聊天功能。 此...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值