一个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的更多相关文章

  1. C++动态内存管理之shared_ptr、unique_ptr

    C++中的动态内存管理是通过new和delete两个操作符来完成的.new操作符,为对象分配内存并调用对象所属类的构造函数,返回一个指向该对象的指针.delete调用时,销毁对象,并释放对象所在的内存 ...

  2. C#下内存管理--垃圾收集

    章节安排 内存管理简介 垃圾回收机制 性能问题 C#下非托管资源的处理 要强调的几点 References 内存管理简介 对于任何一种编程语言,内存管理都是不得不提很重要的一块内容,但可惜的是目前为止 ...

  3. cocos2d-x c++和object-c内存管理比较

    转自:http://www.2cto.com/kf/201307/227142.html 既然选择了C++作为游戏开发的语言, 手动的管理内存是难以避免的, 而Cocos2d-x的仿Objctive- ...

  4. 2、COCOS2D-X内存管理机制

    在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...

  5. boost的内存管理

    smart_ptr raii ( Resource Acquisition Is Initialization ) 智能指针系列的都统称为smart_ptr.包含c++98标准的auto_ptr 智能 ...

  6. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  7. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  8. linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)

    Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...

  9. linux2.6 内存管理——概述

    在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...

随机推荐

  1. AdobeFlashPlayer.资料

    1.chrome 设置 chrome-->设置-->高级-->内容设置-->Flash 2. 3. 4. 5.

  2. 百度地图省市县乡镇街道对应ZOOM级别

    百度地图省市县乡镇街道对应ZOOM级别

  3. Codeforces 429B Working out:dp【枚举交点】

    题目链接:http://codeforces.com/problemset/problem/429/B 题意: 给你一个n*m的网格,每个格子上有一个数字a[i][j]. 一个人从左上角走到右下角,一 ...

  4. NET 平台下的WebService 简单使用

    一句话理解:提供可供外部访问的方法,实现跨平台访问 注意: 在客户端是添加“服务引用”,而不是引用 当服务端更新了服务之后,在客户端,一定也要“更新服务” 当要执行异常调用时,要在前台.aspx的头部 ...

  5. Python基础-多线程与多进程

    一,线程与进程之间的关系:(从知乎上看到的) 一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CP ...

  6. Python习题-登录

    写一个登录的程序,失败次数最多为3次,输入账号.密码错误,提示账号/密码错误.失败三次程序退出,输入正确,提示欢迎xxx登录 i=0while (i<3): username = input(' ...

  7. 13 Python 函数进阶

    代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间 命名空间和作用域 命名空间的本质:存放名字与值的绑定关系 >>> ...

  8. OPcache

    1.介绍 OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销 2.配置 2.1 opcac ...

  9. 关于avpicture_fill 和 sws_scale的关系

    avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB565, pCodecCtx->width, pCodecCtx->h ...

  10. TYVJ P1728 普通平衡树

    P1728 普通平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第一道:普通平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护 ...