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

std::unique_ptr(基础和仿写)

目录

一、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、在工厂模式中作为对象返回;

相关文章:

  • UG旋钮盖模具设计与加工
  • 【JAVA高级】——封装JDBC中的DaoUtils工具类(Object类型方法)
  • MYSQL事务原理分析
  • ORB-SLAM3算法学习—Frame构造—基于SAD滑窗的双目特征匹配
  • 【最佳实践】gorm 联表查询 joins
  • http请求走私漏洞原理,利用,检测,防护
  • simulink中比scope模块还好用的平替出图工具?
  • 微信小程序和H5之间互相跳转、互相传值
  • web前端期末大作业 html+css家乡旅游主题网页设计 湖北武汉家乡介绍网页设计实例
  • PS-HDR图像编辑与应用
  • 2022亚太杯C题思路代码分析
  • 涨知识!Python 的异常信息还能这样展现
  • JDBC编程
  • HTML+CSS期末大作业 中国传统美食网站设计 节日美食13页 html5网页设计作业代码 html制作网页案例代码 html大作业网页代码
  • 基于Java+Spring+Vue+elementUI大学生求职招聘系统详细设计实现
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • CSS相对定位
  • Docker下部署自己的LNMP工作环境
  • extjs4学习之配置
  • HTTP中GET与POST的区别 99%的错误认识
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • Object.assign方法不能实现深复制
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • Sublime text 3 3103 注册码
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 搭建gitbook 和 访问权限认证
  • 给Prometheus造假数据的方法
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端自动化解决方案
  • 深度学习在携程攻略社区的应用
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • ​2021半年盘点,不想你错过的重磅新书
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #大学#套接字
  • $ git push -u origin master 推送到远程库出错
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (Forward) Music Player: From UI Proposal to Code
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .Net Remoting(分离服务程序实现) - Part.3
  • .net 受管制代码
  • .net反编译工具
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • []sim300 GPRS数据收发程序
  • [APIO2015]巴厘岛的雕塑
  • [codeforces] 25E Test || hash
  • [IE9] IE9 beta版下载链接
  • [Java开发之路](14)反射机制