C++内存管理之unique_ptr
一个unique_ptr"拥有“他所指向的对象。与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定的对象。当unique_ptr被销毁时,它所指向的对象也被销毁。uniptr_ptr表达的是一种独占的思想。
初始化
#include <iostream>
#include <memory>
using namespace std; //常规操作
int main(int argc, char *argv[])
{
unique_ptr<double> p1; //!可指向一个double的unique_ptr
unique_ptr<int> p2(new int()); //!p2指向了一个值为42的int unique_ptr<string> pstr(new string("strtest"));
// unique_ptr<string> pstrCopy(pstr); //!error: 不支持对象的拷贝
unique_ptr<string> pstrAssin;
// pstrAssin = pstr //!error: uniptr不支持赋值
return ;
}
unique_ptr一般操作

关于unique_ptr还支持哪些操作,在前面的博文中我也做了总结,请参考该篇文章中图表:https://www.cnblogs.com/wangkeqin/p/9351191.html
unique_ptr所有权转移
虽然我们不能拷贝赋值unique_ptr,但是可以通过调用release或者set将指针的所有权从一个(非const)unique_ptr转移给一个unique:
#include <iostream>
#include <memory> using namespace std; class TEST
{
public:
TEST(const string & name)
:_name(name)
{cout<<"TEST:"<<_name<<endl;}
TEST(const TEST & another)
{ _name = another._name;
cout<<another._name<<" copyStruct "<<_name<<endl;}
TEST & operator =(const TEST & another){
if(&another==this)
return *this;
this->_name=another._name;
cout<<another._name<<" copyAssin to "<<_name<<endl;
}
~TEST(){cout<<"~TEST:"<<_name<<endl;} //private:
string _name;
}; //其他操作
int main()
{
unique_ptr<TEST> p1(new TEST("case_1"));
unique_ptr<TEST> p2(p1.release()); //!将所有权从p1转移到p2,p1现在指向NULL。
cout<<"++++++++++++++++++++++++"<<endl;
unique_ptr<TEST> p3(new TEST("case_2"));
p2.reset(p3.release()); //!p2释放了原来指向的内存,接受了p3指向的内存。
getchar();
}
传递unique_ptr参数和返回unique_ptr
不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或者赋值一个将要被销毁的unique_ptr。其本质就是调用了移动拷贝和移动赋值;最常见的例子是从函数返回一个unique_ptr:
#include <iostream>
#include <memory> using namespace std; class TEST
{
public:
TEST(const string & name)
:_name(name)
{cout<<"TEST:"<<_name<<endl;}
TEST(const TEST & another)
{ _name = another._name;
cout<<another._name<<" copyStruct "<<_name<<endl;}
TEST & operator =(const TEST & another){
if(&another==this)
return *this;
this->_name=another._name;
cout<<another._name<<" copyAssin to "<<_name<<endl;
}
~TEST(){cout<<"~TEST:"<<_name<<endl;} //private:
string _name;
}; //!例外:
//①返回一个即将被销毁的uniptr
unique_ptr<TEST> retDying(string param)
{
return unique_ptr<TEST>(new TEST(param));
} //②返回一个局部对象;
unique_ptr<TEST> retTemp(string param)
{
unique_ptr<TEST> pTemp(new TEST(param));
return pTemp;
} int main()
{
unique_ptr<TEST>ret1 = retDying("dying");
cout<<(*ret1)._name<<endl; unique_ptr<TEST>ret2 = retTemp("temp");
cout<<(*ret2)._name<<endl;
getchar();
}
向后兼容:auto_ptr
标准库较早的版本包含了一个名为auto_ptr的类,它具有unique_ptr的部分特性,但不是全部。特别时我们在容器中保存auto_ptr,也不能从函数中返回auto_ptr。虽然auto_ptr仍然是标准库的一部分,但是编写程序时应该使用unique_ptr。
向unique_ptr传递删除器
类似于shared_ptr,unique_ptr默认情况下也是使用delete释放它指向的对象。与shared_ptr一样,我们可以重载一个unique_ptr中默认的删除器。但是unique_ptr管理删除器的方式与shared_ptr不同,其原因我们将在后面继续补充。
重载一个unique_ptr中的删除器会影响到unique_ptr类型如何构造(或reset)该类型的对象。与重载关联器的比较操作类似。我们必须在尖括号中unique_ptr指向类型之后提供删除器类型。在创建或者reset一个这种unique_ptr这种类型的对象时,必须提供一个指定类型的可调用对象:
#include <stdio.h>
#include <memory>
using namespace std; void closePf(FILE * pf)
{
cout<<"----close pf after works!----"<<endl;
fclose(pf);
cout<<"*****end working****"<<endl;
} int main()
{
// FILE * fp2 = fopen("bin2.txt", "w");
// if(!pf)
// return -1;
// char *buf = "abcdefg";
// fwrite(buf, 8, 1, fp2);
// fclose(fp2);
//______________________________________
// shared_ptr<FILE> pf(fopen("bin2.txt", "w"),closePf);
// cout<<"*****start working****"<<endl;
// if(!pf)
// return -1;
// char *buf = "abcdefg";
// fwrite(buf, 8, 1, pf.get()); //!确保fwrite不会删除指针的情况下,可以将shared_ptr内置指针取出来。
// cout<<"----write int file!-----"<<endl; unique_ptr<FILE,decltype(closePf)*> pf(fopen("bin2.txt", "w"),closePf); //!使用了decltype类型推断
cout<<"*****start working****"<<endl;
if(!pf)
return -;
char *buf = "abcdefg";
fwrite(buf, , , pf.get()); //!确保fwrite不会删除指针的情况下,可以将unique_ptr内置指针取出来。
cout<<"----write int file!-----"<<endl;
return ;
}
使用unique_ptr管理动态数组
标准库提供了一个可以管理new分配动态数组的unique_ptr版本。为了用用一个unique_ptr管理动态数组,我们必须在对象类型后面跟一对空方括号;如此,在unique对象销毁的时候,也可以自动调用delete[ ]而非delete来完成内存的释放。
#include <iostream>
#include <memory>
using namespace std; class ArrTest
{
public:
ArrTest(){
static int i = ;
_i = i;
cout<<" ArrTest()"<<":"<<i++<<endl;
}
~ArrTest(){
static int i = ;
cout<<"~ ArrTest()"<<":"<<i++<<endl;
}
int _i;
}; int main()
{
unique_ptr<ArrTest[]> p(new ArrTest[]);
cout<<p[]._i<<endl; //!获取某个元素值,警告:不要使用越界的下标,unique_ptr也是不检查越界的。
p.reset();
return ;
}

C++内存管理之unique_ptr的更多相关文章
- C++动态内存管理之shared_ptr、unique_ptr
C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...
- C#下内存管理--垃圾收集
章节安排 内存管理简介 垃圾回收机制 性能问题 C#下非托管资源的处理 要强调的几点 References 内存管理简介 对于任何一种编程语言,内存管理都是不得不提很重要的一块内容,但可惜的是目前为止 ...
- cocos2d-x c++和object-c内存管理比较
转自:http://www.2cto.com/kf/201307/227142.html 既然选择了C++作为游戏开发的语言, 手动的管理内存是难以避免的, 而Cocos2d-x的仿Objctive- ...
- 2、COCOS2D-X内存管理机制
在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...
- boost的内存管理
smart_ptr raii ( Resource Acquisition Is Initialization ) 智能指针系列的都统称为smart_ptr.包含c++98标准的auto_ptr 智能 ...
- .NET基础拾遗(1)类型语法基础和内存管理基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...
- PHP扩展-生命周期和内存管理
1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...
- linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)
Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...
- linux2.6 内存管理——概述
在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...
随机推荐
- java 中的拦截器和过滤器
区别: 1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几 ...
- jQuery JS 入门记录
1.类型转换 .toString() 转字符串 . parseInt() parseFloat() 强制转换 数字型(Number) 1.声明 var i = 1; var i = new Numbe ...
- 全面解析Bootstrap手风琴效果
触发手风琴可以通过自定义的data-toggle 属性来触发.其中data-toggle值设置为 collapse,data-target="#折叠区标识符". 第一步:设计一个面 ...
- Python基础-内置函数总结
内置函数 int('123') float() string() tuple() set() dict(name='zdd',age=18) type()#查看类型 len()#看长度,其实是元素的个 ...
- jmeter 多压力机并发测试过程
要实现多台压力机并发,就必须有多台服务器上安装了jmeter程序包,首先把一台服务器作为主压力机,测试脚本放到这台机器上,主压力机与从压力机在同一局域网中,服务器之间可以ping通 第一步:在linu ...
- SQL-INSERT INTO用法
一.单独向表或视图中插入一行数据: insert [into]table_name[(column1,column2,...)]values (value1,value2,...) 说明: 1.int ...
- python字符串相关操作
字符串搜索相关搜索指定字符串,没有返回-1:str.find('t')指定起始位置搜索:str.find('t',start)指定起始及结束位置搜索:str.find('t',start,end)从右 ...
- DFS的简单应用(zoj2110,poj1562)
zoj2110 简单的dfs应用,注意have数组的处理 #include<iostream> #include<cstdio> #include<cstdlib> ...
- JAVA堆内存和栈内存初步了解
一.堆内存和栈内存 程序运行时内存分配有三种:静态存储分配,栈式存储分配,堆式存储分配 1.静态存储分配: 在程序编译时就可以确定数据目标在运行时所需要的内存,因此在编译时就为其分配固定大小的内存. ...
- Java 使用itext生成pdf以及下载
使用方法: 1.需要两个jar包: iText-5.0.6.jar //必须使用该版本,否则缺少相关的方法 TextAsian.jar //是为了文档中正常显示中文所必须引用的包 TextAsi ...