OpenCascade源码剖析:Handle类

Handle其实就是智能指针的上古版本,了解一点C++11的应该对shared_ptr非常熟悉,那么你就把Handle当做shared_ptr来理解就没有任何问题了。

不过OCCT的Handles是侵入式的实现,前面讲过Standard_Transient类提供了引用计数机制,这个就是为了实现Handle

定义Handle

在需要使用Handle的类中,通过宏DEFINE_STANDARD_HANDLE(class_name,ancestor_name)来定义这个类的Hanle,例如给TopoDS_TShape定义一个Handle:

此宏展开后代码如下,可以看到,次宏定义了一个Handle_TopoDS_TShape类,不过这个类是个空壳,其实现基本在基类opencascade::handle<TopoDS_TShape>

class Handle_TopoDS_TShape : public opencascade::handle<TopoDS_TShape> 
{ 
public: 
    Handle_TopoDS_TShape() {} 
    Handle_TopoDS_TShape(opencascade::handle<TopoDS_TShape>&& theHandle) : opencascade::handle<TopoDS_TShape>(theHandle) 
    {
    } 
    template <class T2, typename = typename std::enable_if <std::is_base_of <TopoDS_TShape,T2>::value>::type> 
    inline Handle_TopoDS_TShape(const opencascade::handle<T2>& theOther) : opencascade::handle<TopoDS_TShape>(theOther) 
    {
    } 
    template <class T2, typename = typename std::enable_if <std::is_base_of <TopoDS_TShape,T2>::value>::type> 
    inline Handle_TopoDS_TShape(const T2* theOther) : opencascade::handle<TopoDS_TShape>(theOther) 
    {
    } 
    template<typename T> inline Handle_TopoDS_TShape& operator=(T theOther) 
    { 
        opencascade::handle<TopoDS_TShape>::operator=(theOther);  
        return *this; 
    } 
};

Handle的实现

opencascade::handle是一个模板类,该类实现了共享智能指针的基本功能

  • BeginScope,EndScope用于更新引用计数,管理生命周期
  • 拷贝,赋值,移动,逻辑运算等函数或运算符的实现
  • DownCast类型转换,向上类型转换
namespace opencascade {

  template <class T>
  class handle
  {
  public:
    typedef T element_type;

  public:
    handle () : entity(0) {}

    handle (const T *thePtr) : entity(const_cast<T*>(thePtr))
    {
      BeginScope();
    }

    handle (const handle& theHandle) : entity(theHandle.entity)
    {
      BeginScope();
    }

    handle (handle&& theHandle) noexcept : entity(theHandle.entity)
    {
      theHandle.entity = 0;
    }

    ~handle ()
    {
      EndScope();
    }

    void Nullify()
    {
      EndScope();
    }

    bool IsNull() const { return entity == 0; } 

    void reset (T* thePtr)
    {
      Assign (thePtr);
    }

    handle& operator= (const handle& theHandle)
    {
      Assign (theHandle.entity);
      return *this;
    }

    handle& operator= (const T* thePtr)
    {
      Assign (const_cast<T*>(thePtr));
      return *this;
    }

    handle& operator= (handle&& theHandle) noexcept
    {
      std::swap (this->entity, theHandle.entity);
      return *this;
    }

    T* get() const { return static_cast<T*>(this->entity); }

    T* operator-> () const { return static_cast<T*>(this->entity); }

    T& operator* () const { return *get(); }

    template <class T2>
    bool operator== (const handle<T2>& theHandle) const
    { 
      return get() == theHandle.get();
    }

    template <class T2>
    bool operator== (const T2 *thePtr) const
    { 
      return get() == thePtr;
    }

    template <class T2>
    friend bool operator== (const T2 *left, const handle& right)
    {
      return left == right.get();
    }

    template <class T2>
    bool operator!= (const handle<T2>& theHandle) const
    {
      return get() != theHandle.get();
    }

    template <class T2>
    bool operator!= (const T2 *thePtr) const
    {
      return get() != thePtr;
    }

    template <class T2>
    friend bool operator!= (const T2 *left, const handle& right)
    {
      return left != right.get();
    }

    template <class T2>
    bool operator< (const handle<T2>& theHandle) const
    { 
      return get() < theHandle.get();
    }

    template <class T2>
    static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
      DownCast (const handle<T2>& theObject)
    {
      return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
    }

    template <class T2>
    static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type 
      DownCast (const T2* thePtr)
    {
      return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));
    }

    template <class T2>
    __declspec(deprecated("down-casting from object of the same or unrelated type is meaningless"))
    static handle DownCast (const handle<T2>& theObject, typename opencascade::std::enable_if<!is_base_but_not_same<T2, T>::value, void*>::type = 0)
    {
      return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
    }

    template <class T2>
    __declspec(deprecated("down-casting from object of the same or unrelated type is meaningless"))
    static handle DownCast (const T2* thePtr, typename opencascade::std::enable_if<!is_base_but_not_same<T2, T>::value, void*>::type = 0)
    {
      return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));
    }

    explicit operator bool () const
    { 
      return entity != nullptr;
    }

    template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>
    operator const handle<T2>& () const
    {
      return reinterpret_cast<const handle<T2>&>(*this);
    }

    template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>
    operator handle<T2>& ()
    {
      return reinterpret_cast<handle<T2>&>(*this);
    }

  private:
    void Assign (Standard_Transient *thePtr)
    {
      if (thePtr == entity)
        return;
      EndScope();
      entity = thePtr;
      BeginScope();
    }

    void BeginScope()
    {
      if (entity != 0)
        entity->IncrementRefCounter();
    }

    void EndScope()
    {
      if (entity != 0 && entity->DecrementRefCounter() == 0)
        entity->Delete();
      entity = 0;
    }

    template <class T2> friend class handle;

  private:
    Standard_Transient* entity;
  };
} 

至于为什么需要弄一个Handle_TopoDS_TShape空壳类而不是直接模板实现就可以(一般只能指针都是一个模板类即可),应该是历史包袱问题,毕竟上古时期,编译器可能都不太支持模板。

Handle的一些问题

循环引用

标准库外的野鸡版本共享智能指针基本上都会有头疼的循环依赖问题,毕竟C++也是到了21世纪20年代才通过引入一个weak_ptr才解决shared_ptr的循环引用问题,这也不是大问题,避免循环依赖,或者手动打断依赖即可

性能问题

  • 避免频繁down cast
  • 避免拷贝

线程安全

Handle不是线程安全的,所以,上锁吧?

类型转换

DownCast的实现是dynamic_cast,这个就有点半拉子了,上篇讲到Standard_Transient自己实现了RTTI,而dynamic_cast依托于C++自带的RTTI,相当于双重性能消耗。一般追求性能的系统,自己实现RTTI时,可以实现安全的Cast函数,并且禁用dynamic_cast。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/440667.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Missing type map configuration or unsupported mapping

今天开发的时候突然遇到这么一个问题&#xff0c;可以确定的是不是AutoMap的问题&#xff0c;因为项目中其他接口都是好好的&#xff0c;只有新加的这个控制器不行&#xff0c;排查了一下&#xff0c;少了映射配置&#xff0c;在这里加上映射关系即可&#xff0c;大意了。

egg如何写单元测试

优秀的代码需要有单元测试进行质量保证&#xff0c;每个测试用例都给应用的稳定性提供了一层保障。 测试目录结构 我们约定 test 目录为存放所有测试脚本的目录&#xff0c;测试所使用到的 fixtures 和相关辅助脚本都应该放在此目录下。 测试文件的目录和我们需要测试的文件目…

HTML—常用标签

常用标签&#xff1a; 标题标签&#xff1a;<h1></h1>......<h6></h6>段落标签&#xff1a;<p></p>换行标签&#xff1a;<br/>列表&#xff1a;无序列表<ul><li></li></ul> 有序列表<ol>&…

Python的数据库编程基础知识

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd;如果停止&#xff0c;就是低谷&#xf…

[HackMyVM]靶场 Zeug

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

力扣hot100:240.搜索二维矩阵II(脑子)

吉大21级算法分析与设计的一道大题&#xff0c;由于每一行都是排好序的直接逐行二分 可以达到&#xff1a;O(mlogn)。但是这里追求更广的思路可以使用其他方法。 矩阵四分&#xff1a; 在矩阵中用中心点比较&#xff0c;如果target大于中心点的值&#xff0c;则由于升序排列&am…

排序二叉树

参考 Binary Search Tree Visualization (usfca.edu) 一、构建排序二叉树 注意引用 tree /*** 构造二叉排序树* param tree* param x*/ void buildTree(BSTree &tree,ElementType &x){if (treeNULL){tree(BSTree) calloc(1, sizeof(BSTNode));tree->datax;//注意ret…

Python算法题集_搜索二维矩阵

Python算法题集_搜索二维矩阵 题51&#xff1a;搜索二维矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵展开为列表二分法】2) 改进版一【行*列区间二分法】3) 改进版二【第三方模块】 4. 最优算法5. 相关资源 本文为Python算法题集之…

bugku-misc隐写

下载文件&#xff0c;解压得到图片 没看到信息&#xff0c;试着查看图片属性 看到图片宽高不一致&#xff0c;猜测可能需要改变图片长度或者宽度 试着把图片变大&#xff0c;十进制500转16进制 得到1f4 用010打开图片 第二行第一个为宽&#xff0c;第二个为高&#xff0c;A…

【计网】TCP协议安全与风险:深入探讨网络通信的基石

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 &#x1f310;前言 &#x1f512;正文 TCP (Transmission Control Protocol): UDP (User Datagram Protocol): HTTP (Hypertext Transfer …

WordPress建站入门教程:如何创建菜单和设置前端导航菜单?

前面我们跟大家分享了WordPress如何上传安装WordPress主题&#xff0c;但是启用主题后前端没有看到有导航菜单&#xff0c;这是因为我们还没有创建菜单和设置导航菜单。 JianYue主题导航菜单和右上角菜单 今天boke112百科就继续跟大家分享WordPress站点如何创建菜单和设置前端…

java-抢红包一些简单概念

抢红包&#xff0c;比如微信中抢红包&#xff0c;红包金额分配使用的是二倍均值算法。 二倍均值拆包&#xff1a; 拆包要求:所有人抢到的金额之和等于红包总额&#xff0c;每个人最少抢到 0.01 元&#xff0c;每个人抢到的红包金额不要相差太大二倍均值法:假设红包总金额是X&…

2024最新版正规视频影视系统源码/APP+H5视频影视源码

全新魅思V20正规视频影视系统源码&#xff0c;APPH5视频影视源码。会员花费三千购入的&#xff0c;具体搭建教程放压缩包了&#xff01; 有兴趣的下载自行研究吧&#xff0c;搭建一共要用到3个域名&#xff0c;可以拿二级域名搭建。

奖励建模(Reward Modeling)实现人类对智能体的反馈

奖励建模&#xff08;Reward Modeling&#xff09;是强化学习中的一个重要概念和技术&#xff0c;它主要用于训练智能体&#xff08;如AI机器人或大型语言模型&#xff09;如何更有效地学习和遵循人类期望的行为。在强化学习环境中&#xff0c;智能体通过尝试不同的行为获得环境…

4月9日至10日Hack.Summit 2024亚洲首秀:Web3开发者齐聚香港数码港

Hack.Summit() 是一系列 Web3 开发者大会。本届活动将于 2024 年 4 月 9 日至 4 月 10 日在香港数码港举行。自十年前首次举办以来&#xff0c;此次会议标志着 Hack.Summit() 首次在亚洲举办&#xff0c;香港被选为首次亚洲主办城市&#xff0c;这对 Hack VC 和该地区都具有重要…

【Servlet】Servlet 详解(使用+原理)

文章目录 1. Servlet 介绍1.1 什么是 Servlet1.2 Servlet 的主要工作 2. Servlet 程序创建步骤2.1 创建项目2.2 引入依赖2.3 创建目录2.4 编写代码2.5 打包程序2.6 部署程序2.7 验证程序 3. 使用 Smart Tomcat 进行部署3.1 安装 Smart Tomcat3.2 配置 Smart Tomcat3.3 使用 Sma…

React-Redux中actions

一、同步actions 1.概念 说明&#xff1a;在reducers的同步修改方法中添加action对象参数&#xff0c;在调用actionCreater的时候传递参数&#xff0c;数会被传递到action对象payload属性上。 2.reducers对象 说明&#xff1a;声明函数同时接受参数 const counterStorecre…

【Python】科研代码学习:三 PreTrainedModel, PretrainedConfig

【Python】科研代码学习&#xff1a;三 PreTrainedModel, PretrainedConfig 前言Models : PreTrainedModelPreTrainedModel 中重要的方法 tensorflow & pytorch 简单对比Configuration : PretrainedConfigPretrainedConfig 中重要的方法 前言 HF 官网API 本文主要从官网AP…

乐高EV3硬件编程

文章目录&#xff1a; 一&#xff1a;软件 1.软件下载安装 2.软件的使用 二&#xff1a;乐高EV3电子元器件介绍 1.针对不同的版本 2.组合起来看 3.元器件栏 绿色部分&#xff1a;动作 橙色部分&#xff1a;流程控制 黄色部分&#xff1a;传感器 红色部分&#xff1…

【PyTorch】进阶学习:探索BCEWithLogitsLoss的正确使用---二元分类问题中的logits与标签形状问题

【PyTorch】进阶学习&#xff1a;探索BCEWithLogitsLoss的正确使用—二元分类问题中的logits与标签形状问题 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、Py…