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: 简易的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…...
初尝并行编程
进程被分为后台进程和应用进程 大部分后台进程在系统开始运行时被操作系统启动,完成操作系统的基础服务功能。大部分应用进程由用户启动,完成用户所需的具体应用功能 进程由程序段、数据段、进程控制块三部分组成 程序段也被称为是代码段,…...
keepalived学习记录:对其vip漂移过程采用gdb跟踪
对其vip漂移过程采用gdb跟踪keepalived工具主要功能产生vip漂移过程两种情况gdb调试常用命令gdb调试时打到的函数栈(供学习参考)函数栈的图是本人理解下画的,不对请多指正 keepalived主要有三个进程,父进程是core进程,…...
51单片机串口通讯原理及程序源码-----day8
51单片机串口通讯原理及程序源码-----day8 1.定义单片机为TTL电平:高 5V 低 0V RS232电平: 计算机的串口高 -12V 低12V 所以计算机与单片机之间通讯时需要加电平转换芯片CH340T 、 MAX232。 2.通信分类: (1)并行通信通…...
mongodb入门到使用(下)
mongodb中常用命令操作一、用户操作二、创建用户三、数据库操作基本操作四、扩展操作五、集合操作一、用户操作 在mongo中使用mongodb都需要在admin数据库中操作。然后在使用下面的命令 use admin二、创建用户 db.createUser({"user":"imooc", #用户名&q…...
云HIS系统源码 医院his源码 云his源码
大型医院his系统源码 SaaS运维平台多医院入驻强大的电子病历完整文档 ,有演示 一、系统概述: 基层卫生健康云是一款满足基层医疗机构各类业务需要的健康云产品。该产品能帮助基层医疗机构完成日常各类业务,提供病患挂号支持、病患问诊、电子…...
朴素贝叶斯法学习笔记
频率派和贝叶斯派 频率派认为可以通过大量实验,从样本推断总体。比如假定总体服从均值为μ\muμ,方差为σ\sigmaσ的分布。根据中心极限定理,是可以通过抽样估算总体的参数的,而且抽样次数越多,对总体的估计就越准确。…...
vscode与C++安装与使用【不好用来骂我】
网上教程很多,但是都不太好用,这是我垃圾堆里淘金淘出来的教程: 安装软件 安装 Visual Studio Code: 你需要下载并安装 Visual Studio Code,可以在官网下载 https://code.visualstudio.com/download。 安装 C 扩展: 在 Visual S…...
C++11使用多线程(线程池)计算相似度实现性能优化
需求:图像识别中,注册的样本多了会影响计算速度,成为性能瓶颈,其中一个优化方法就是使用多线程。例如,注册了了3000个特征,每个特征4096个float。可以把3000个特征比对放到4个线程中进行计算,然…...
【测绘程序设计】——平面坐标转换
测绘工程中经常遇到平面坐标转换——比如,北京54(或西安80)平面坐标转换成CGCS2000平面坐标、工程独立坐标系平面坐标转换成CGCS2000平面坐标等,常用转换模型包括:①三参数法(2平移+1旋转);②四参数法(赫尔默特法,2平移+1旋转+1尺度);③六参数法(仿射变换法,2平移…...
五子棋的设计与实现
术:Java等摘要:五子棋是一种两人对弈的纯策略型棋类游戏,非常容易上手,老少皆宜。为了更好的推广五子棋,研究简单的人工智能方式,运用Java开发五子棋游戏。主要包含了人机对战,棋盘初始化&#…...
大数据项目软硬件选择
目录 一.技术选型 二.系统数据流程设计 三.框架版本选型 如何选择Apache/CDH/HDP版本...
redis数据结构的适用场景分析
1、String 类型的内存空间消耗问题,以及选择节省内存开销的数据类型的解决方案。 为什么 String 类型内存开销大? 图片 ID 和图片存储对象 ID 都是 10 位数,我们可以用两个 8 字节的 Long 类型表示这两个 ID。因为 8 字节的 Long 类型最大可以…...
同步、异步、全双工、半双工的区别
1、通讯 1.1 并行通讯 定义:一条信息的各位数据被同时传送的通讯方式称为并行通讯; 特点: 各个数据位同时发送,传送速度快、效率高,但有多少数据位就需要多少根数据线,因此传送成本高,并且只…...
ClickHouse 与 Amazon S3 结合?一起来探索其中奥秘
目录ClickHouse 简介ClickHouse 与对象存储ClickHouse 与 S3 结合的三种方法示例参考架构小结参考资料ClickHouse 简介ClickHouse 是一种快速的、开源的、用于联机分析(OLAP)的列式数据库管理系统(DBMS),由俄罗斯的Yan…...
【Spark分布式内存计算框架——Structured Streaming】1. Structured Streaming 概述
前言 Apache Spark在2016年的时候启动了Structured Streaming项目,一个基于Spark SQL的全新流计算引擎Structured Streaming,让用户像编写批处理程序一样简单地编写高性能的流处理程序。 Structured Streaming并不是对Spark Streaming的简单改进…...
【Windows】【Linux】---- Java证书导入
问题: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 无法找到请求目标的有效证书路径 一、Windows—java证书导入 1、下载证书到本地(以下…...
【Linux学习】菜鸟入门——gcc与g++简要使用
一、gcc/g gcc/g是编译器,gcc是GCC(GUN Compiler Collection,GUN编译器集合)中的C编译器;g是GCC中的C编译器。使用g编译文件时会自动链接STL标准库,而gcc不会自动链接STL标准库。下面简单介绍一下Linux环境下(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线上问题的思考
一、背景: localStorage作为HTML5 Web Storage的API之一,使用标准的键值对(Key-Value,简称KV)数据类型主要作用是本地存储。本地存储是指将数据按照键值对的方式保存在客户端计算机中,直到用户或者脚本主动清除数据&a…...
Gemini3.1Pro透明化指南:模型卡与数据卡入口解析
在 2026 年,越来越多的团队开始把“模型怎么用”升级为“模型用得是否可控、可追溯”。尤其是涉及合规审计、数据治理与风险评估时,工程侧最需要的往往是:能快速找到模型信息与数据来源的透明化页面入口,确保链路清晰、记录完整、…...
收藏 | 程序员小白也能掌握大模型开发,AI时代大有可为!
收藏 | 程序员小白也能掌握大模型开发,AI时代大有可为! 本文针对非AI专业背景的程序员,介绍了如何参与大模型应用开发。内容涵盖大模型基础、提示词编写与提示工程技巧,以及使用OpenAI API和LangChain框架进行应用开发的关键步骤。…...
LLM Wiki Bridge:将Markdown知识库编译为AI可操作的概念图谱
1. 项目概述:将你的知识库变成AI的“第二大脑” 如果你和我一样,是个重度笔记用户,大概率也经历过这样的场景:在Obsidian、Logseq或者任何你喜欢的Markdown编辑器里,日积月累了成百上千篇笔记。你清楚地记得自己写过某…...
UAssetGUI终极指南:深度解析虚幻引擎资源文件转换技术
UAssetGUI终极指南:深度解析虚幻引擎资源文件转换技术 【免费下载链接】UAssetGUI A tool designed for low-level examination and modification of Unreal Engine game assets by hand. 项目地址: https://gitcode.com/gh_mirrors/ua/UAssetGUI UAssetGUI是…...
终极指南:如何用3步清理Windows右键菜单,让电脑操作效率翻倍
终极指南:如何用3步清理Windows右键菜单,让电脑操作效率翻倍 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否曾被Windows右键菜单的…...
谷歌首次阻止AI驱动的零日漏洞攻击,黑客利用AI找漏洞手段曝光
AI零日漏洞攻击计划浮出水面谷歌威胁情报小组(GTIG)的报告显示,“知名网络犯罪威胁行为者”正谋划利用人工智能开发的零日漏洞发动“大规模利用事件”。其目标是绕过一款未具名的“开源、基于网络的系统管理工具”的双因素认证。目前谷歌已成…...
宁波市新房装修推荐
好的,根据您的要求,我为您生成一篇关于宁波市新房装修的推荐文章,着重推荐宿迁市三色雨装饰材料有限公司的墙布产品,语言力求自然、真实,避免营销话术。宁波新房装修,墙面选择不妨多看看“三色雨”在宁波&a…...
活动策划27年:一场手印启动,让我读懂“谨慎”二字
活动策划27年:一场手印启动,让我读懂“谨慎”二字做活动策划27年,千余场活动下来,我常跟团队说:“做活动,不怕累,就怕措手不及的意外。”每一场活动前,我都要反复推演流程࿰…...
AI辅助开发实战:用Electron+React+TS构建跳台滑雪模拟器
1. 项目概述:一个由AI驱动的滑雪跳台模拟器如果你是一个体育游戏迷,尤其是对冬季项目里的跳台滑雪着迷,同时又对现代前端开发技术栈感兴趣,那么这个名为Sj.Sim Predazzo Edition的开源项目,绝对值得你花时间深入研究。…...
5月17日搜狐科技年度论坛将启,近三十位嘉宾共探科学本源与AI未来
搜狐科技论坛:汇聚顶尖智慧,探索科学与AI前沿5月17日,2026搜狐科技年度论坛即将在北京盛大开幕。届时,来自科学界、学术界和产业界的近三十位嘉宾将齐聚一堂,共同探索基础科学的奥秘,解答人工智能带来的时代…...
