IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【NS3】对象模型和智能指针 -> 正文阅读

[C++知识库]【NS3】对象模型和智能指针

对象模型

理解程序设计的最佳切入点?——对象模型

对象模型的作用?

一、单个类的管理。(基类与子类)
尽管每个类表示的网络元素不同,但它们往往都具有某些相同的功能需求,如动态内存管理和属性配置等。没必要在每一个类中分别实现这些需求。因此需要一些顶层的基类来统一定义与实现这些共性特征。而子类只需关注自身专属特性即可。

二、多个类的管理。(关联各个类)
任何一个单一的类时无法完成网络模拟的。这些类需要被有机地关联起来,形成一个可以处理各种网络事件的独立主题。例如,一个网络结点需要整合应用程序、通信信道、网络设备和TCP/IP层协议等多个C++类才能与其他结点进行通信。这些类之间如何灵活、高效的关联,也是对象模型解决的问题之一。

如何实现上述目的?

定义三个基类:SimpleRefCountObjectBaseObject

SimpleRefCount:解决针对单个类的动态内存管理问题,智能指针的实现。

ObjectBase解决单个类需要配置属性和trace变量的需求。

Object类解决了多个类之间动态关联问题。
这种类之间的动态关联是通过一种叫做对象聚合的功能实现的。简单地说,对象聚合能够让一个Object对象在运行时动态地关联其他对象,而不是在编译时关联。

下图给出了上面三个基类的继承关系,以及它们各自的一些子类代表。箭头指向的类是基类。
在这里插入图片描述

智能指针

为什么使用智能指针?

传统的动态内存是从new运算符创建到被delete运算符销毁。尽管这种设计增加了内存管理的灵活度,但同时造成了两个严重的安全隐患。

内存泄漏:动态内存没有被及时释放
空悬指针:在尚有其他指针引用的情况下释放动态内存

智能指针如何解决这两个安全隐患的呢?

除了与常规指针有着相似的行为(拷贝、赋值等),更重要的是其能够自动释放那些没有指针指向的动态内存,从而避免了内存泄漏和空悬指针问题,提高了程序的安全性。

如何实现智能指针?

智能指针由PtrSimpleRefCount两个类模板组成。
其中,SimpleRefCount类是ns-3智能指针的内部实现。它定义了一个引用计数器来记录指向自身内存的指针数量。
Ptr类则定义了ns-3智能指针的外部接口

设计原理

Ptr使用范式

Ptr<类名>指针变量名

Ptr的实现

两部分:
第一部分负责保存原始指针和模拟原始指针操作(复制、赋值),这一部分通过Ptr实现;
第二部分负责记录所有指向所分配的对象内存的指针数量(引用计数器),这一部分通过SimpleRefCount实现。

下面的代码中,模板形参T(typename T)是Ptr指针指向对象的类名称。指向对象内存的原始指针m_ptr保存在Ptr类中。
SimpleRefCount类定义了一个引用计数器m_count变量。

这段代码还包括SimpleRefCount类的Ref()Unref()函数,分别负责计数器值的增减,当计数器变为0时,意味着没有任何指针指向该内存,这时,Unref()函数会调用删除函数销毁对象。
在这里插入图片描述
类模板

Ref()和Unref()函数怎么使用?

定义一个SimpleRefCount的子类MyTestPtr指针t1t2分别指向两个MyTest对象。

Ptr<MyTest>t1 = Create<MyTest>();
Ptr<MyTest>t2 = Create<MyTest>();

t2 = t1; //t1指向t2???

由于赋值操作使得MyTest_2获得了一个新的Ptr指针t1,因此t1在指向新内存之后立即调用MyTest_2Ref()函数,使其计数器加1,变为2。相反,MyTest_1对象在这个过程中失去了原来的Ptr指针t1,因此在t1指向新内存之前会调用MyTest_1Unref()函数,使其计数器减1。此时,MyTest_1的计数器会变为0,被销毁。

在这里插入图片描述

使用实例

  1. 初始化
Packet *p = NULL;
Ptr<Packet>ptr;
  1. 创建对象
//使用Packet()构造函数
Packet *p      = new Packet();
Ptr<Packet>ptr = Create<Packet>();

//使用Packet(uint32_t size)构造函数
Packet *p      = new Packet(100);
Ptr<Packet>ptr = Create<Packet>(100);
  1. 赋值操作
Packet *p        = new Packet();
Ptr<Packet>ptr_1 = p;
Ptr<Packet>ptr_2 = ptr; //???
  1. 指针运算
ptr->GetUid();    //->
(*ptr).GetUid();  //*

一个是指针指向的函数,一个是指针解引用之后的函数,但这两行最后都会执行函数,效果相同。

  1. 比较运算
if(ptr == ptr_1){}
if(ptr != ptr_1){}
if(ptr == p){}
if(ptr != p){}

等于和不等于符号可以用于两个Ptr指针之间,也可以用于一个Ptr指针和一个原始指针之间。

if(ptr < ptr_1){}
if(ptr <= ptr_1){}
if(ptr > ptr_1){}
if(ptr >= ptr_1){}
  1. 流插入
std::cout<<"address:"<<ptr<<std::endl;

输出Ptr指针中原始指针的地址。

  1. 拷贝
    Ptr指针的拷贝有两种:指针拷贝对象拷贝

指针拷贝:
被拷贝的和新的Ptr指针均指向同一个对象。

Packet *p = new Packet();
Ptr<Packet>ptr(p);
Ptr<Packet>ptr_1(ptr); //Packet对象计数器加1

对象拷贝:
使用的场景:不只需要一个新的指针,还需要拷贝出一个新的对象,开辟新的内存空间。这时候就需要用到Copy()函数。
使用比较少。

Ptr<Packet>ptr = Create<Packet>();
Ptr<Packet>ptr_1 = Copy(ptr);//ptr_1指向一个新创建的Packet对象
  1. 类型转换
    ns-3提供了DynamicCast()StaticConst()ConstCast()三个Ptr指针类型转换函数。
    注意:每次调用这些函数后,都需要检查其返回Ptr指针是否为空,确认转换是否成功
//DynamicCast
Ptr<NetDevice>pDev = Create<LoopbackNetDevice>();
Ptr<LoopbackNetDevice>pLoopDev = DynamicCast<LoopbackNetDevice>(pDev);
if(!pLoopDev )
	NS_LOG_UNCOND("DynamicCast failure");

//StaticCast
Ptr<LoopbackNetDevice>pLoopDev1 = StaticCast<LoopbackNetDevice>(pDev);
if(!pLoopDev1 )
	NS_LOG_UNCOND("StaticCast failure");

//ConstCast
Ptr<Packet const>ptr = Create<Packet>();
Ptr<Packet>ptr_1 = ConstCast<Packet>(ptr);
if(!ptr_1)
	NS_LOG_UNCOND("ConstCast failure");
  1. 获取原始指针
    获取原始指针有两个函数:PeekPointer()GetPointer()
    GetPointer()会对Ptr指针指向对象的计数器加1。相当于新创建了一个指针指向这个对象。使用极少。
    PeekPointer()则没有这个要求。
Ptr<Packet>ptr = Create<Packet>();
Packet *p = PeekPointer(ptr);

适用范围

Ptr的作用
提供了和原始指针相同的操作集,实现了内存的动态管理。

局限性:

  • 只能支持构造函数参数少于或等于7个的类。
  • 只能引用与SimpleRefCount子类对象。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-07 22:27:40  更:2022-04-07 22:28:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:01:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码