std::unique_ptr(基础和仿写)

news2025/8/13 5:42:18

目录

一、C++参考手册说明

1、解释注释

2、 参考代码

二、对std::unique_ptr分析

1、创建一个unique_ptr

2、无法进行复制构造和赋值操作

3、可以进行移动赋值

4.可以返回unique——ptr

5、管理动态数组

6、在容器中保存指针

三、对std::unique_ptr设计

1、对于的那个对象

2、对于一组对象

四、std::unique_ptr使用场景


一、C++参考手册说明

1、解释注释

2、 参考代码

#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>
 
struct B {
  virtual void bar() { std::cout << "B::bar\n"; }
  virtual ~B() = default;
};
struct D : B
{
    D() { std::cout << "D::D\n";  }
    ~D() { std::cout << "D::~D\n";  }
    void bar() override { std::cout << "D::bar\n";  }
};
 
// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}
 
void close_file(std::FILE* fp) { std::fclose(fp); }
 
int main()
{
  std::cout << "unique ownership semantics demo\n";
  {
      auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
      auto q = pass_through(std::move(p)); 
      assert(!p); // 现在 p 不占有任何内容并保有空指针
      q->bar();   // 而 q 占有 D 对象
  } // ~D 调用于此
 
  std::cout << "Runtime polymorphism demo\n";
  {
    std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
                                                  // 作为指向基类的指针
    p->bar(); // 虚派发
 
    std::vector<std::unique_ptr<B>> v;  // unique_ptr 能存储于容器
    v.push_back(std::make_unique<D>());
    v.push_back(std::move(p));
    v.emplace_back(new D);
    for(auto& p: v) p->bar(); // 虚派发
  } // ~D called 3 times
 
  std::cout << "Custom deleter demo\n";
  std::ofstream("demo.txt") << 'x'; // 准备要读的文件
  {
      std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),
                                                           close_file);
      if(fp) // fopen 可以打开失败;该情况下 fp 保有空指针
        std::cout << (char)std::fgetc(fp.get()) << '\n';
  } // fclose() 调用于此,但仅若 FILE* 不是空指针
    // (即 fopen 成功)
 
  std::cout << "Custom lambda-expression deleter demo\n";
  {
    std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
        {
            std::cout << "destroying from a custom deleter...\n";
            delete ptr;
        });  // p 占有 D
    p->bar();
  } // 调用上述 lambda 并销毁 D
 
  std::cout << "Array form of unique_ptr demo\n";
  {
      std::unique_ptr<D[]> p{new D[3]};
  } // 调用 ~D 3 次
}

 

二、对std::unique_ptr分析

1、创建一个unique_ptr

#include<iostream>
int main() {
	std::unique_ptr<int> pInt(new int(5));
	std::cout << *pInt;
}

2、无法进行复制构造和赋值操作

#include<iostream>
int main() {
	std::unique_ptr<int> pInt2(pInt);//报错
	std::unique_ptr<int> pInt3 = pInt;//报错
}

3、可以进行移动赋值

#include<iostream>
int main() {
	std::unique_ptr<int> pInt(new int(5));
	std::unique_ptr<int> pInt2(pInt);//报错
	std::unique_ptr<int> pInt3 = pInt;//报错
	std::unique_ptr<int> pInt4 = std::move(pInt);//移动赋值

	std::cout << *pInt;
}

4.可以返回unique——ptr


std::unique_ptr<int> clone(int a) {
	std::unique_ptr<int> pInt(new int(a));
	return pInt;
}
int main() {
	clone(5);
	std::cout << *clone(5);
}

5、管理动态数组

int main() {
	std::unique_ptr<int[]> p(new int[5]{ 1,2,3,4,5 });
	p[0] = 0;
}

6、在容器中保存指针

int main() {
	std::vector<std::unique_ptr<int>> vec;
	std::unique_ptr<int> pInt(new int(5));
	vec.push_back(std::move(pInt));
	return 0;
}

三、对std::unique_ptr设计

1、对于的那个对象

#ifndef MY_UNIQUE_PTR
#define MY_UNIQUE_PTR
#include<iostream>
using namespace std;
template<class _T>
class MyDeletor
{
public:
	MyDeletor() {}
	void operator()(_T* ptr)const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};
template <class _Ty, class _Dx = MyDeletor<_Ty>>
class my_unique_ptr
{
private:
	_Ty* _Ptr;
	_Dx _myDeletor;
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using delete_type = _Dx;
public:
	my_unique_ptr(const my_unique_ptr&) = delete;
	my_unique_ptr& operator=(const my_unique_ptr&) = delete;
	my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) { cout << "Create my_unique_ptr" << this << endl; }
	~my_unique_ptr() {
		if (_Ptr != nullptr)
		{
			_myDeletor(_Ptr);
			_Ptr = nullptr;
		}
		cout << " delete my_unique_ptr" << this << endl;
	}
	my_unique_ptr(my_unique_ptr&& _Y)
	{
		_Ptr = _Y._Ptr;
		_Y._Ptr = nullptr;
		cout << "move copy my_unique_ptr:" << this << endl;
	}
	template <class _Uy>
	my_unique_ptr& operator=(_Uy* _Y)
	{
		if (this->_Ptr == (pointer)_Y)return this;
		if (_Ptr != nullptr) { _myDeletor(_Ptr); }
		_Ptr = _Y;
		return *this;
	}
	my_unique_ptr& operator=(my_unique_ptr&& _Y)
	{
		if (this == &_Y) return *this;
		//reset(_Y.release());
		if (_Ptr != nullptr) _myDeletor(_Ptr);
		_Ptr = _Y._Ptr;
		_Y._Ptr = nullptr;
		cout << "move operatoe=: " << this << endl;
		return *this;
	}
	_Dx& get_deleter()
	{
		return _myDeletor;
	}
	const _Dx& get_deleter()const
	{
		return _myDeletor;
	}
	_Ty& operator*()const
	{
		return *_Ptr;
	}
	pointer operator ->()const
	{
		return _Ptr;
	}
	operator bool()const
	{
		return _Ptr != nullptr;
	}
	pointer get()const
	{
		return _Ptr;
	}
	pointer release()
	{
		_Ty* old = _Ptr;
		_Ptr = nullptr;
		return old;
	}
	void reset(pointer _P = nullptr)
	{
		pointer old = _Ptr;
		_Ptr = _P;
		if (old != nullptr)
		{
			_myDeletor(old);
		}
	}
	void swap(my_unique_ptr _Y)
	{
		std::swap(_Ptr, _Y._Ptr);
		std::swap(_myDeletor, _Y._myDeletor);
	}

};

2、对于一组对象

template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
	MyDeletor() = default;
	void operator()(_Ty* ptr)const
	{
		if (ptr != nullptr)
		{
			delete[]ptr;
		}
	}
};
template <class _Ty, class _Dx >
class my_unique_ptr<_Ty[], _Dx>
{
private:
	_Ty* _Ptr;
	_Dx _myDeletor;
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using delete_type = _Dx;
public:
	my_unique_ptr(const my_unique_ptr&) = delete;
	my_unique_ptr& operator=(const my_unique_ptr&) = delete;
	my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) { cout << "Create my_unique_ptr" << this << endl; }
	~my_unique_ptr() {
		if (_Ptr != nullptr)
		{
			_myDeletor(_Ptr);
			_Ptr = nullptr;
		}
		cout << " delete my_unique_ptr" << this << endl;
	}
	my_unique_ptr(my_unique_ptr&& _Y)
	{
		_Ptr = _Y._Ptr;
		_Y._Ptr = nullptr;
		cout << "move copy my_unique_ptr:" << this << endl;
	}
	my_unique_ptr& operator=(my_unique_ptr&& _Y)
	{
		if (this == &_Y) return *this;
		reset(_Y.release());
		/*if (_Ptr != nullptr) _myDeletor(_Ptr);
		_Ptr = _Y._Ptr;
		_Y._Ptr = nullptr;*/
		cout << "move operatoe=: " << this << endl;
		return *this;
	}
	_Dx& get_deleter()
	{
		return _myDeletor;
	}
	const _Dx& get_deleter()const
	{
		return _myDeletor;
	}
	_Ty& operator*()const
	{
		return *_Ptr;
	}
	pointer operator ->()const
	{
		return &**this;
	}
	operator bool()const
	{
		return _Ptr != nullptr;
	}
	pointer get()const
	{
		return _Ptr;
	}
	pointer release()
	{
		_Ty* old = _Ptr;
		_Ptr = nullptr;
		return old;
	}
	void reset(pointer _P = nullptr)
	{
		pointer old = _Ptr;
		_Ptr = _P;
		if (old != nullptr)
		{
			_myDeletor(old);
		}
	}
	void swap(my_unique_ptr _Y)
	{
		std::swap(_Ptr, _Y._Ptr);
		std::swap(_myDeletor, _Y._myDeletor);
	}
	_Ty& operator [](size_t _Index)const
	{
		return _Ptr[_Index];
	}

};
template<class _Ty, class ..._Type>
my_unique_ptr<_Ty>my_make_unique(_Type&&..._arys)
{
	return my_unique_ptr<_Ty>(new _Ty(_arys...));
}

四、std::unique_ptr使用场景

  • 1、语义简单,即使不确定使用的指针是不是被分享所有权的时候,默选unique_ptr独占式所有权,当确定要被分享时转换为shareed_ptr;
  • 2、unique_ptr效率比shared_ptr高,不需要维护引用计数和背后的控制块;
  • 3、unique_ptr用起来更顺畅,选择性更多,可以转换shared_ptr和通过get和release定制化智能指针
  • 4、在工厂模式中作为对象返回;

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于生命周期的面试题vue

1.第一次进入到页面&#xff08;组件&#xff09;会执行哪些生命周期 beforeCreate 》 没有data&#xff0c;没有elcreated 》 有data&#xff0c;没有elbeforeMount 》 有data&#xff0c;没有el&#xff08;其实已经在准备了&#xff09;mounted 》 有data&#xff0c;有el …

SRM供应商管理系统有什么作用?

目前国内稍具规模的企业都导入了企业资源管理ERP系统&#xff0c;实现了内部管理数字化转型&#xff0c;提升了内部各部门之间的协同能力。但是企业供应链管理涉及大量的外部资源&#xff0c;特别是数量庞大的供应商资源&#xff0c;而大部分的ERP系统很难实现采购同供应商之间…

感恩节,感谢2022的转变,有在好好生活!

疫情之下的感恩节 原来今天是感恩节。2022年快要结束了&#xff0c;在这样一个特别的节日里&#xff0c;就不写技术类文章了&#xff0c;写一写我的2022年&#xff0c;这一年&#xff0c;我的学习、工作和生活都有发生改变&#xff0c;感谢过去的时光&#xff0c;改变让我有在…

Linux下:文件与路径、用户管理、常用命令、vim

文章目录第一章&#xff1a; Linux文件与路径1.1 文件结构1.2 基本概念1.3 基本命令信息1.3.1 查看linux 系统信息&#xff08;修改主机名&#xff09;1.3.2 ls1.3.3 cd/pwd1.3.4 pushd命令创建目录栈 第二章&#xff1a; 文件/目录的创建、删除、复制、阅读2.1 mkdir2.2 touc…

书籍Java8 实战 笔记

第5章 使用流 本章内容 1.筛选、切片和匹配 2.查找、匹配和归约 3.使用数值范围等数值流 4.从多个源创建流 5.无限流 5.1 筛选和切片 用谓词筛选&#xff0c;筛选出各不相同的元素&#xff0c;忽略流中的头几个元素&#xff0c;或将流截短至指定长度。 5.1.1 用谓词筛选 就是…

【优化分配】粒子群算法求解火车票分配优化问题【含Matlab源码 1137期】

⛄一、粒子群算法简介 1 引言 自然界中的鸟群和鱼群的群体行为一直是科学家的研究兴趣所在。生物学家Craig Reynolds在1987年提出了一个非常有影响的鸟群聚集模型&#xff0c;在他的仿真中&#xff0c;每一个个体都遵循&#xff1a;避免与邻域个体相撞&#xff1a;匹配邻域个体…

vue3+vite中使用vuex

前言&#xff1a; 在vue3vite创建的项目中使用vuex&#xff0c;要注意的是vite有部分写法和之前的webpack是不同的&#xff0c;比如&#xff0c;他不支持 require&#xff0c;想把vue2的项目直接升级到vue3的时候&#xff0c;需要改很多地方&#xff0c;如果非要使用vite也可以…

Caffeine《二》

《Caffeine&#xff08;Java顶级缓存组件&#xff09;二》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《Caffeine&#xff08;Java顶级缓存组件&#xff09;》《Caffeine&#xff08;Java顶级缓存组件&#xff09;二》8. 缓存驱逐算法8.1 FIFO(First …

ThingsBoard源码解析-设备连接

整体流程 在MqttTransportHandler中进行Mqtt消息处理&#xff0c;以AccessToken认证的设备举例&#xff0c;核心处理流程如下&#xff1a; //MqttTransportHandler 132 processMqttMsg(ctx, (MqttMessage) msg); //MqttTransportHandler 154 processConnect(ctx, (MqttConne…

视频文件转换器有哪些?什么视频文件转换器好用?

视频承载着丰富的文字、声音、图像&#xff0c;能够多维度地调用人的感知能力&#xff0c;可以说是当今时代信息输入的重要载体。 而视频有avi、rm、rmvb、3 gp等多种格式&#xff0c;当我们使用不同设备来观看视频时&#xff0c;就涉及到视频文件格式转换这一问题&#xff0c;…

RabbitMQ系列【14】备份交换机

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录前言代码实现测试前言 在之前&#xff0c;我们分析了消息可靠性之发布确认、退回机制。当消息到达交换机后&#xff0c;但是没有找到匹配的队列时&#xff0c;退回模式&#xff08;return&…

ms10-046漏洞利用+bypassuac提权

目录 前期准备 漏洞利用 上传文件到目标主机 UAC介绍 使用bypassuac模块绕过uac进行提权。 关于钓鱼链接的拓展 前期准备 Win xp sp3关闭防火墙 实验前提 保证连通性&#xff0c;进行互ping 漏洞利用 进入msf查看需要利用的漏洞&#xff1a;ms10-046 search ms10-046 …

【Kafka】单分区单副本增加至多分区多副本

一、背景 系统&#xff1a;CentOS Linux release 7.9.2009 (Core) Kafka版本&#xff1a;2.11-2.0.0.3.1.4.0-315 [scala版本2.11&#xff1b;kafka 2.0.0版本&#xff1b;基于ambari3.1.4.0-315的版本 ] 二、现象 业务系统中总是报警&#xff1a;kafka消费延迟。 三、问题…

nodejs+vue+elementui线上买菜系统

本线上买菜系统主要包括三大功能模块&#xff0c;即管理员和用户。 &#xff08;1&#xff09;管理员模块&#xff1a;首页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理。 &#xff08;2&#xff09;前台&#xff1a;商品信息、公告信息、个人中心、…

java语言概述

目录 JDK和JRE的说明 Java语言的环境搭建 常用的DOS命令 第一个Java程序 创建java源文件 Hello.java 编译 步骤三&#xff1a;运行 总结 注 释(comment) JDK和JRE的说明 关系说明图 2、 概念说明 JDKJREJAVA开发工具&#xff08;javac.exe java.exe、javaboc.exe&…

SpringIoc依赖查找-5

1. 依赖查找的今世前生: Spring IoC容器从Java标准中学到了什么? 单一类型依赖查找 JNDI - javax.naming.Context#lookup(javax.naming.Name) JavaBeans - java.beans.beancontext.BeanContext 集合类型依赖查找 java.beans.beancontext.BeanContext 集合查找方法 层…

基于android的移动学习平台(前端APP+后端Java和MySQL)

一、需求规格说明书 1&#xff0e;概述 1.1项目目的与目标, &#xff08;1&#xff09; 项目目的&#xff1a;设计并实现网络化的在线学习系统&#xff0c;对校内课程教学进行辅助&#xff0c;为学生和教师提供一个良好的互动平台&#xff0c;方便学生课后获取学习资源和进行交…

阿里云负载均衡SLB,HTTPS动态网站部署负载均衡,实现高并发流量分发

第一步购买服务器&#xff0c;测的话一般就用按量付费几毛钱一小时 我是用了三台&#xff0c;一台是常用的服务器&#xff0c;两台临时服务器进行部署项目 2&#xff1a;服务器购买完之后&#xff0c;开始安装项目运行环境&#xff0c;我是宝塔一键按键的&#xff0c;PHP7.1。…

新知实验室-基于腾讯云音视频TRTC的微信小程序实践

前言 腾讯会议是我们常用的一款线上会议软体&#xff0c;如果想要使用&#xff0c;我们需要下载软体使用&#xff0c;相比之下&#xff0c;基于腾讯云音视频的TRTC提供了一个很好的解决方案&#xff0c;我们通过接入到小程序中来实现快捷的开始会议&#xff0c;加入会议。 TR…

[Power Query] 删除错误/空值

数据导入后&#xff0c;有可能出现错误(Error)或者空值(null) &#xff0c;我们需要对此进行删除。为此&#xff0c;本文通过讲解Power Query中的删除错误/空值操作&#xff0c;帮助大家的同时也便于日后自身的复盘学习 数据源 将数据源导入到Power BI Desktop&#xff0c;单击…