c++中unique_ptr 的使用和理解
unique_ptr 的使用
std::unique_ptr是c++11起引入的智能指针,为什么必须要在c++11起才有该特性,主要还是c++11增加了move语义,否则无法对对象的所有权进行传递。
unique_ptr 介绍
- unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。建议将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使unique_ptr,而当构造 unique_ptr 时,可使用make_unique 函数。make_unique函数是从C++14之后才有。
- std::unique_ptr 实现了独享所有权的语义。一个非空的 std::unique_ptr 总是拥有它所指向的资源。转移一个 std::unique_ptr 将会把所有权也从源指针转移给目标指针(源指针被置空)。拷贝一个 std::unique_ptr 将不被允许,因为如果你拷贝一个 std::unique_ptr ,那么拷贝结束后,这两个 std::unique_ptr 都会指向相同的资源,它们都认为自己拥有这块资源(所以都会企图释放)。因此 std::unique_ptr 是一个仅能移动(move_only)的类型。当指针析构时,它所拥有的资源也被销毁。默认情况下,资源的析构是伴随着调用 std::unique_ptr 内部的原始指针的 delete 操作的。
示例程序
- 示例程序1
#include <memory>
#include <iostream>
#include <utility>
class Foo{
public:
Foo() = default;
Foo(int a):_a(a) {}
~Foo() {}
int get_a(){
return _a;
}
void set_a(int a) {
_a = a;
}
private:
int _a;
};
std::unique_ptr<Foo> change_a(std::unique_ptr<Foo> f)
{
f->set_a(10);
return f;
}
int main()
{
// std::make_unique是c++14才有
std::unique_ptr<Foo> pf = std::make_unique<Foo>(10);
// unique_ptr的复制构造函数和拷贝构造函数是删除了的,这样保证了对象独占,如果不是独占,那么跟shared_ptr
// 就是一样的功能了。
// std::unique_ptr<Foo> pf1 = pf; // compile error
// 按值传参,会有拷贝问题,同上
// auto p = change_a(pf); //compile error
auto p = change_a(std::move(pf));
std::cout << "get_a = " << p->get_a() << std::endl;
if(!pf)
{
std::cout << "pf is nullptr" << std::endl;
}
//owner transfer from function
std::unique_ptr<Foo> pf2 = std::make_unique<Foo>(11);
std::unique_ptr<Foo> p2 = change_a(std::move(pf2));
std::cout << "get_a = " << p2->get_a() << std::endl;
if(!pf2)
{
std::cout << "pf2 is nullptr" << std::endl;
}
//使用reset
pf2.reset(new Foo(12));
std::cout << "pf2 is not null: " << pf2->get_a() << std::endl;
//release获取原始指针
Foo* ff = pf2.release();
if(!pf2)
{
std::cout << "pf2 is nullptr" << std::endl;
}
std::cout << "ff is not null: " << ff->get_a() << std::endl;
return 0;
}
输出结果
get_a = 10
pf is nullptr
get_a = 10
pf2 is nullptr
pf2 is not null: 12
pf2 is nullptr
ff is not null: 12
- 示例程序2
#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>
// helper class for runtime polymorphism demo below
struct B
{
virtual ~B() = default;
virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B
{
D() { std::cout << "D::D\n"; }
~D() { std::cout << "D::~D\n"; }
void bar() override { std::cout << "D::bar\n"; }
};
// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
p->bar();
return p;
}
// helper function for the custom deleter demo below
void close_file(std::FILE* fp)
{
std::fclose(fp);
}
// unique_ptr-based linked list demo
struct List
{
struct Node
{
int data;
std::unique_ptr<Node> next;
};
std::unique_ptr<Node> head;
~List()
{
// destroy list nodes sequentially in a loop, the default destructor
// would have invoked its `next`'s destructor recursively, which would
// cause stack overflow for sufficiently large lists.
while (head)
{
auto next = std::move(head->next);
head = std::move(next);
}
}
void push(int data)
{
head = std::unique_ptr<Node>(new Node{data, std::move(head)});
}
};
int main()
{
std::cout << "1) Unique ownership semantics demo\n";
{
// Create a (uniquely owned) resource
std::unique_ptr<D> p = std::make_unique<D>();
// Transfer ownership to `pass_through`,
// which in turn transfers ownership back through the return value
std::unique_ptr<D> q = pass_through(std::move(p));
// p is now in a moved-from 'empty' state, equal to nullptr
assert(!p);
}
std::cout << "\n" "2) Runtime polymorphism demo\n";
{
// Create a derived resource and point to it via base type
std::unique_ptr<B> p = std::make_unique<D>();
// Dynamic dispatch works as expected
p->bar();
}
std::cout << "\n" "3) Custom deleter demo\n";
std::ofstream("demo.txt") << 'x'; // prepare the file to read
{
using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
if (fp)
std::cout << char(std::fgetc(fp.get())) << '\n';
} // `close_file()` called here (if `fp` is not null)
std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n";
try
{
std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
{
std::cout << "destroying from a custom deleter...\n";
delete ptr;
});
throw std::runtime_error(""); // `p` would leak here if it were a plain pointer
}
catch (const std::exception&) { std::cout << "Caught exception\n"; }
std::cout << "\n" "5) Array form of unique_ptr demo\n";
{
std::unique_ptr<D[]> p(new D[3]);
} // `D::~D()` is called 3 times
std::cout << "\n" "6) Linked list demo\n";
{
List wall;
const int enough{1'000'000};
for (int beer = 0; beer != enough; ++beer)
wall.push(beer);
std::cout.imbue(std::locale("en_US.UTF-8"));
std::cout << enough << " bottles of beer on the wall...\n";
} // destroys all the beers
}
输出
1) Unique ownership semantics demo
D::D
D::bar
D::~D
2) Runtime polymorphism demo
D::D
D::bar
D::~D
3) Custom deleter demo
x
4) Custom lambda-expression deleter and exception safety demo
D::D
destroying from a custom deleter...
D::~D
Caught exception
5) Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D
6) Linked list demo
1,000,000 bottles of beer on the wall...
c++中unique_ptr 的使用和理解的更多相关文章
- C#中对IDisposable接口的理解
http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html C#中对IDisposable接口的理解 本人最近接触一个项目,在这个项目里面看到很多类实现了 ...
- js中的回调函数的理解和使用方法
js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...
- [BS-18] 对OC中不可变类的理解
对OC中不可变类的理解 OC中存在很多不可变的类(如NSString,NSAttributedString,NSArray,NSDictionary,NSSet等),用它们创建的对象存在于堆内存中,但 ...
- oracle中 connect by prior 递归算法 -- 理解
oracle中 connect by prior 递归算法 -- 理解 http://blog.163.com/xxciof/blog/static/7978132720095193113752/ ...
- MVC架构中的Repository模式 个人理解
关于MVC架构中的Repository模式 个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接 ...
- 关于MySQL中的自联结的通俗理解
关于MySQL中的自联结的通俗理解 前言:最近在通过SQL必知必会这本书学习MySQL的基本使用,在学习中也或多或少遇到了点问题,我也正好分享给大家,我的这篇博客用到的所有表格的代码都是来自SQL必知 ...
- 关于Autosar中的NM模块的理解
本篇文章主要介绍AutoSar中关于NM模块的理解. 阅读本篇文章希望达到的目的: 1. NM(网络管理)是用来做什么的: 2. AutoSar中网络管理的原理: 3.项目实例介绍 1. NM(网络管 ...
- Spring中Bean及@Bean的理解
Spring中Bean及@Bean的理解 Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法: 一.Bean是啥 1.Java面向对象,对象有方法和属性, ...
- Oracle中rownum和rowid的理解
rownum,rowid都叫伪列. 但是,rownum是逻辑上的编号,且其值总是从1开始,每行的rounum不是固定的.而rowid是“物理”编号.若数据库文件没有移动,则每行的 rowid一般是固定 ...
- 【转】C#中对IDisposable接口的理解
IDisposable接口定义:定义一种释放分配的资源的方法. .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资 ...
随机推荐
- selenium配置远程测试环境
开头 因为测试的时候需要不断打开浏览器,这样效率感觉不高,于是想着能不能开启一个浏览器,然后通过代码直接链接来调试就好了. 前提 要先安装好selenium 和 会查看配置自己的google版本和路径 ...
- 2023-02-24:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,采用YUV420P转YUV420SP的方式。
2023-02-24:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,采用YUV420P转YUV420SP的方式. 答案2023-02-24: 使用 github.com ...
- 2020-11-27:go中,map的读流程是什么?
福哥答案2020-11-27:[答案来自此链接:](https://www.bilibili.com/video/BV1Nr4y1w7aa?p=12)源码位于runtime/map.go文件中的map ...
- 2021-07-14:接雨水。给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
2021-07-14:接雨水.给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水. 福大大 答案2021-07-14: 左右指针向中间移动.左指针是左边柱 ...
- Django4全栈进阶之路3 apps.py 文件
在 Django 4 中,每个应用(app)都需要定义一个 apps.py 文件,用于配置应用的基本信息,如应用的名称.显示名称.图标.默认路径.启动时需要执行的操作等.apps.py 文件是一个 P ...
- Vue选日期滚动条自动定位到选定的日期位置
html 这里的关键点就是 :id="'scroll'+index" 以及 :scroll-into-view="intoIndex" <view c ...
- Burpsuite抓包工具的使用
一.打开工具 1处箭头为 代理127.0.0.1 端口8080 2处箭头为 证书 将证书ca下载到桌面上 选择第一个 选择下载到桌面即可 可以修改其后缀为der 此即为证书文件 此处使用火狐浏览器为示 ...
- mysql安装教程【安装版】和Navicat-for-MySQL破解版
傻瓜式mysql安装教程[安装版]https://blog.csdn.net/qq_59636442/article/details/123058454 Navicat-for-MySQL下载链接:h ...
- js 之三 鼠标和键盘事件处理
鼠标和键盘事件 鼠标常见的事件,按下onmousedown,拖动onmounsemove,松开onmousevtup,滚轮等事件: 开发需求: 当鼠标点击控件,进行拖拽,控件跟随鼠标移动: 拖拽事件需 ...
- drf之频率类源码
1 频率类 写一个类,继承SimpleRateThrottle,重写get_cache_key,返回[ip,用户id]什么,就以什么做限制,编写类属性 scope = 字符串,在配置文件中配置 'DE ...