当前位置: 首页 > news >正文

C++Primer16.1.6节练习

练习16.28:

简易的shared_ptr代码如下

#include <iostream>
#include <vector>
#include <list>
using namespace std;//shared_ptr模板
template<typename T>class SharedPtr {friend SharedPtr<T>& MakeShared(T* t);
public://默认初始化SharedPtr() :ptr(nullptr), user(nullptr) { }//传入指向T的指针进行构造,防止隐式类型转换explicit SharedPtr(T* p = nullptr) :ptr(p), user(new size_t(1)) { }//拷贝构造SharedPtr(const SharedPtr& sp) :ptr(sp.ptr), user(sp.user){if (user != nullptr){++* user;}}//析构函数~SharedPtr();//赋值运算符SharedPtr& operator=(const SharedPtr&);//解引用运算符T& operator*() { return *ptr; }//常量版本T& operator*()const { return *ptr; }//返回指针T* get() { return ptr; }size_t use_count() { return *user; }bool unique(){if (use_count == 1){return true;}else{return false;}}private://指向T类型的指针T* ptr;//指向计数器的指针size_t* user;
};//定义make_shared
template<typename T>
SharedPtr<T> MakeShared(T* t)
{T* ptr = t;return SharedPtr<T>(ptr);
}//赋值运算符
template<typename T>
SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr& sp)
{if (this != sp){if (user == nullptr){--* user;if (*user == 0){delete ptr;delete user;}}ptr = sp.ptr;if (sp.user != nullptr){++* sp.user;}user = sp.user;}return *this;
}//析构函数
template<typename T>
SharedPtr<T>::~SharedPtr()
{if (user != nullptr){--* user;if (*user == 0){delete ptr;delete user;}}
}int main()
{SharedPtr<string>sp1(new string("hello"));SharedPtr<string>sp2 = MakeShared<string>(new string("world"));SharedPtr<int>sp3 = MakeShared<int>(new int(666));cout<<*sp1<<endl;cout << *sp2 << endl;cout << *sp3 << endl;system("pause");return 0;
}

结果如下:

 unique_ ptr代码如下:

#include <iostream>
#include <vector>
#include <list>
using namespace std;//shared_ptr模板
template<typename T>class UniquePtr {
public://默认初始化UniquePtr() :ptr(nullptr){ }//传入指向T的指针进行构造,防止隐式类型转换explicit UniquePtr(T* p) :ptr(p) { }//析构函数~UniquePtr();//不能拷贝,不能赋值运算符,定义为删除的函数UniquePtr(const UniquePtr&) = delete;UniquePtr& operator=(const UniquePtr&) = delete;//解引用运算符T& operator*() { return *ptr; }//常量版本T& operator*()const { return *ptr; }//u放弃对指针的控制权,返回指针,并将u置为空T* release();//释放u指向的对象,如果传入了内置指针,则使u指向这个对象,否则指控void reset();void reset(T* p);private://指向T类型的指针T* ptr;
};//u放弃对指针的控制权,返回指针,并将u置为空
template<typename T>
T* UniquePtr<T>::release()
{auto temp = ptr;if (ptr != nullptr){ptr == nullptr;}return temp;
}//释放u指向的对象,如果传入了内置指针,则使u指向这个对象,否则指控
template<typename T>
void UniquePtr<T>::reset()
{if (ptr != nullptr){delete ptr;ptr == nullptr;}
}template<typename T>
void UniquePtr<T>::reset(T* p)
{if (ptr != nullptr){delete ptr;}ptr = p;
}//析构函数
template<typename T>
UniquePtr<T>::~UniquePtr()
{if (ptr != nullptr){delete ptr;}
}int main()
{UniquePtr<string>sp1(new string("hello"));UniquePtr<string>sp2;UniquePtr<int>sp3(new int(666));cout << *sp1 << endl;cout << *sp3 << endl;cout << endl;sp2.reset(new string("world"));sp1.release();system("pause");return 0;
}

结果为:

 

练习16.29:

#include <iostream>
#include <vector>
#include <list>
using namespace std;//shared_ptr模板
template<typename T>class SharedPtr {friend SharedPtr<T>& MakeShared(T* t);
public://默认初始化SharedPtr() :ptr(nullptr), user(nullptr) { }//传入指向T的指针进行构造,防止隐式类型转换explicit SharedPtr(T* p = nullptr) :ptr(p), user(new size_t(1)) { }//拷贝构造SharedPtr(const SharedPtr& sp) :ptr(sp.ptr), user(sp.user){if (user != nullptr){++* user;}}//析构函数~SharedPtr();//赋值运算符SharedPtr& operator=(const SharedPtr&);//解引用运算符T& operator*() { return *ptr; }//常量版本T& operator*()const { return *ptr; }//返回指针T* get() { return ptr; }size_t use_count() { return *user; }bool unique(){if (use_count == 1){return true;}else{return false;}}private://指向T类型的指针T* ptr;//指向计数器的指针size_t* user;
};template<typename T, class ...Args>
SharedPtr<T>MakeShared(Args&&...args)
{return SharedPtr<T>(new T(std::forward<Args>(args)...));
}//赋值运算符
template<typename T>
SharedPtr<T>& SharedPtr<T>::operator=(const SharedPtr& sp)
{if (this != sp){if (user == nullptr){--* user;if (*user == 0){delete ptr;delete user;}}ptr = sp.ptr;if (sp.user != nullptr){++* sp.user;}user = sp.user;}return *this;
}//析构函数
template<typename T>
SharedPtr<T>::~SharedPtr()
{if (user != nullptr){--* user;if (*user == 0){delete ptr;delete user;}}
}//声明,类模板与函数模板的声明
template<typename>class BlobPtr;
template<typename>class Blob;
template<typename>class SharedPtr;
template<typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>class Blob {//每个Blob实例将访问权限授予用相同类型实例化的BlobPtr和相等运算符friend class BlobPtr<T>;friend class SharedPtr<T>;//template<typename X>friend class BlobPtr<T>;friend bool operator==<T>(const Blob<T>&, const Blob<T>&);//template<typename X>friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
public:typedef T value_type;typedef typename std::vector<T>::size_type size_type;Blob();Blob(std::initializer_list<T>il);//模板构造函数template<typename It>Blob(It b, It e);size_type size()const { return (*data).size(); }bool empty()const { return (*data).element_type(); }void push_back(const T& t) { (*data).push_back(t); }//移动版本void push_back(T&& t) { (*data).push_back(std::move(t)); }void pop_back();//元素访问T& back()const;T& operator[](size_type i);BlobPtr<T> begin() { return BlobPtr<T>(*this); }BlobPtr<T> end(){auto ret = BlobPtr<T>(*this, (*data).size());return ret;}T& front()const;private:SharedPtr<std::vector<T>>data;//data[i]无效,则抛出msgvoid check(size_type i, const std::string& msg)const;
};template<typename T>
T& Blob<T>::front()const
{check(0, "front on empty Blob");return data->front();
}//check
template<typename T>
void Blob<T>::check(size_type i, const std::string& msg)const
{if (i >= data->size()){throw std::out_of_range(msg);}
}//back
template<typename T>
T& Blob<T>::back()const
{check(0, "back on empty Blob");return data->back();
}//下标运算符
template<typename T>
T& Blob<T>::operator[](size_type i)
{check(i, "subscript out of range");return (*data)[i];
}//pop函数
template<typename T>
void Blob<T>::pop_back()
{check(0, "pop_back on empty Blob");data->pop_back();
}//构造函数
template<typename T>
Blob<T>::Blob() :data(MakeShared<std::vector<T>>()) { }//接受initializer_list的构造函数
template<typename T>
Blob<T>::Blob(std::initializer_list<T>il) : data(MakeShared<std::vector<T>>(il)) { }//若试图访问一个不存在的元素,BlobPtr抛出一个异常
template<typename T>class BlobPtr {
public:BlobPtr() :curr(0) { }BlobPtr(Blob<T>& a, size_t sz = 0) :wptr(a.data), curr(sz) { }T& operator*()const{auto p = check(curr, "dereference past end");return (*p)[curr];}//递增与递减BlobPtr& operator++();BlobPtr& operator--();BlobPtr& operator++(int);BlobPtr& operator--(int);T& deref() const;BlobPtr& incr();private:std::shared_ptr<std::vector<T>>check(std::size_t, const std::string&)const;std::weak_ptr<std::vector<T>>wptr;std::size_t curr;
};template<typename T>
T& BlobPtr<T>:: deref()const
{auto p = check(curr, "dereference past end");return (*p)[curr];
}template<typename T>
BlobPtr<T>& BlobPtr<T>::incr()
{//递增curr,判断curr位于合理位置,不合理位置不递增check(curr, "incrasement past end of BlobPtr");++curr;return *this;
}template<typename T>
BlobPtr<T>& BlobPtr<T>::operator++(int)
{BlobPtr ret = *this;++* this;return ret;
}template<typename T>
BlobPtr<T>& BlobPtr<T>::operator--(int)
{BlobPtr ret = *this;--* this;return ret;
}template<typename T>
BlobPtr<T>& BlobPtr<T>::operator++()
{check(curr, "increment past end of BlobPtr");++curr;return *this;
}template<typename T>
BlobPtr<T>& BlobPtr<T>::operator--()
{check(curr, "decrement past begin of BlobPtr");++curr;return *this;
}int main()
{Blob<int>b1 = { 1,2,3,4,5,6,7,8,9 };cout << b1.size() << endl;system("pause");return 0;
}

结果如下:

练习16.30:

见练习16.29

练习16.31:

shared_ptr是运行时绑定删除器,而unique_ptr则是编译时绑定删除器。unqiue_ptr有两个模板参数,一个是所管理的对象类型,另一个是删除器类型。因此,删除器类型是unique_ptr类型的一部分,在编译时就可知道,删除器可直接保存在unique_ptr对象中。通过这种方式,unique_ptr避免了间接调用删除器的运行时开销,而编译时还可以将自定义的删除器,如DebugDelete编译为内联形式 

相关文章:

C++Primer16.1.6节练习

练习16.28&#xff1a; 简易的shared_ptr代码如下 #include <iostream> #include <vector> #include <list> using namespace std;//shared_ptr模板 template<typename T>class SharedPtr {friend SharedPtr<T>& MakeShared(T* t); public…...

初尝并行编程

进程被分为后台进程和应用进程 大部分后台进程在系统开始运行时被操作系统启动&#xff0c;完成操作系统的基础服务功能。大部分应用进程由用户启动&#xff0c;完成用户所需的具体应用功能 进程由程序段、数据段、进程控制块三部分组成 程序段也被称为是代码段&#xff0c;…...

keepalived学习记录:对其vip漂移过程采用gdb跟踪

对其vip漂移过程采用gdb跟踪keepalived工具主要功能产生vip漂移过程两种情况gdb调试常用命令gdb调试时打到的函数栈&#xff08;供学习参考&#xff09;函数栈的图是本人理解下画的&#xff0c;不对请多指正 keepalived主要有三个进程&#xff0c;父进程是core进程&#xff0c;…...

51单片机串口通讯原理及程序源码-----day8

51单片机串口通讯原理及程序源码-----day8 1.定义单片机为TTL电平&#xff1a;高 5V 低 0V RS232电平&#xff1a; 计算机的串口高 -12V 低12V 所以计算机与单片机之间通讯时需要加电平转换芯片CH340T 、 MAX232。 2.通信分类&#xff1a; &#xff08;1&#xff09;并行通信通…...

mongodb入门到使用(下)

mongodb中常用命令操作一、用户操作二、创建用户三、数据库操作基本操作四、扩展操作五、集合操作一、用户操作 在mongo中使用mongodb都需要在admin数据库中操作。然后在使用下面的命令 use admin二、创建用户 db.createUser({"user":"imooc", #用户名&q…...

云HIS系统源码 医院his源码 云his源码

大型医院his系统源码 SaaS运维平台多医院入驻强大的电子病历完整文档 &#xff0c;有演示 一、系统概述&#xff1a; 基层卫生健康云是一款满足基层医疗机构各类业务需要的健康云产品。该产品能帮助基层医疗机构完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子…...

朴素贝叶斯法学习笔记

频率派和贝叶斯派 频率派认为可以通过大量实验&#xff0c;从样本推断总体。比如假定总体服从均值为μ\muμ&#xff0c;方差为σ\sigmaσ的分布。根据中心极限定理&#xff0c;是可以通过抽样估算总体的参数的&#xff0c;而且抽样次数越多&#xff0c;对总体的估计就越准确。…...

vscode与C++安装与使用【不好用来骂我】

网上教程很多&#xff0c;但是都不太好用&#xff0c;这是我垃圾堆里淘金淘出来的教程&#xff1a; 安装软件 安装 Visual Studio Code: 你需要下载并安装 Visual Studio Code&#xff0c;可以在官网下载 https://code.visualstudio.com/download。 安装 C 扩展: 在 Visual S…...

C++11使用多线程(线程池)计算相似度实现性能优化

需求&#xff1a;图像识别中&#xff0c;注册的样本多了会影响计算速度&#xff0c;成为性能瓶颈&#xff0c;其中一个优化方法就是使用多线程。例如&#xff0c;注册了了3000个特征&#xff0c;每个特征4096个float。可以把3000个特征比对放到4个线程中进行计算&#xff0c;然…...

【测绘程序设计】——平面坐标转换

测绘工程中经常遇到平面坐标转换——比如,北京54(或西安80)平面坐标转换成CGCS2000平面坐标、工程独立坐标系平面坐标转换成CGCS2000平面坐标等,常用转换模型包括:①三参数法(2平移+1旋转);②四参数法(赫尔默特法,2平移+1旋转+1尺度);③六参数法(仿射变换法,2平移…...

五子棋的设计与实现

术&#xff1a;Java等摘要&#xff1a;五子棋是一种两人对弈的纯策略型棋类游戏&#xff0c;非常容易上手&#xff0c;老少皆宜。为了更好的推广五子棋&#xff0c;研究简单的人工智能方式&#xff0c;运用Java开发五子棋游戏。主要包含了人机对战&#xff0c;棋盘初始化&#…...

大数据项目软硬件选择

目录 一.技术选型 二.系统数据流程设计 三.框架版本选型 如何选择Apache/CDH/HDP版本...

redis数据结构的适用场景分析

1、String 类型的内存空间消耗问题&#xff0c;以及选择节省内存开销的数据类型的解决方案。 为什么 String 类型内存开销大&#xff1f; 图片 ID 和图片存储对象 ID 都是 10 位数&#xff0c;我们可以用两个 8 字节的 Long 类型表示这两个 ID。因为 8 字节的 Long 类型最大可以…...

同步、异步、全双工、半双工的区别

1、通讯 1.1 并行通讯 定义&#xff1a;一条信息的各位数据被同时传送的通讯方式称为并行通讯&#xff1b; 特点&#xff1a; 各个数据位同时发送&#xff0c;传送速度快、效率高&#xff0c;但有多少数据位就需要多少根数据线&#xff0c;因此传送成本高&#xff0c;并且只…...

ClickHouse 与 Amazon S3 结合?一起来探索其中奥秘

目录ClickHouse 简介ClickHouse 与对象存储ClickHouse 与 S3 结合的三种方法示例参考架构小结参考资料ClickHouse 简介ClickHouse 是一种快速的、开源的、用于联机分析&#xff08;OLAP&#xff09;的列式数据库管理系统&#xff08;DBMS&#xff09;&#xff0c;由俄罗斯的Yan…...

【Spark分布式内存计算框架——Structured Streaming】1. Structured Streaming 概述

前言 Apache Spark在2016年的时候启动了Structured Streaming项目&#xff0c;一个基于Spark SQL的全新流计算引擎Structured Streaming&#xff0c;让用户像编写批处理程序一样简单地编写高性能的流处理程序。 Structured Streaming并不是对Spark Streaming的简单改进&#xf…...

【Windows】【Linux】---- Java证书导入

问题&#xff1a; PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 无法找到请求目标的有效证书路径 一、Windows—java证书导入 1、下载证书到本地&#xff08;以下…...

【Linux学习】菜鸟入门——gcc与g++简要使用

一、gcc/g gcc/g是编译器&#xff0c;gcc是GCC(GUN Compiler Collection&#xff0c;GUN编译器集合)中的C编译器&#xff1b;g是GCC中的C编译器。使用g编译文件时会自动链接STL标准库&#xff0c;而gcc不会自动链接STL标准库。下面简单介绍一下Linux环境下&#xff08;Windows差…...

Cadence Allegro 导出Bill of Material Report详解

⏪《上一篇》   🏡《总目录》   ⏩《下一篇》 目录 1,概述2,Assigned Functions Report作用3,Assigned Functions Report示例4,Assigned Functions Report导出方法4.1,方法14.2,方法2B站关注“硬小二”浏览更多演示视频...

localStorage线上问题的思考

一、背景&#xff1a; localStorage作为HTML5 Web Storage的API之一&#xff0c;使用标准的键值对&#xff08;Key-Value,简称KV&#xff09;数据类型主要作用是本地存储。本地存储是指将数据按照键值对的方式保存在客户端计算机中&#xff0c;直到用户或者脚本主动清除数据&a…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...