unique_ptr常用操作、删除器、尺寸[转]

unique_ptr常用操作、删除器、尺寸[转]

目录

unique_ptr常用操作、删除器、尺寸[转]

unique_ptr概述

常规初始化

unique_ptr和new配合

make_unique 函数

unique_ptr常用操作

unique_ptr不支持的操作

移动语义

release():

reset()

= nullptr

指向一个数组

get()

*解引用

swap():

智能指针名字作为判断条件

转换成shared_ptr类型

返回unique_ptr

指定删除器

指定删除器额外说明

尺寸问题

智能指针总结

unique_ptr概述

  • 独占式的概念(专属所有权):同一个时刻,只能有一个unique_ptr指针指向这个对象(这块内存);
  • 当这个unique_ptr被销毁的时候,它所指向的对象也被销毁
  • 格式:
unique_ptr<指向的对象类型> 智能指针变量名:

常规初始化

unique_ptr和new配合

unique_ptr<int> pi; //可以指向int对象的一个空智能指针
if (pi == nullptr){
	cout << "pi目前还是空指针" << endl;
}

unique_ptr<int> pi2(new int(105)); // 此时pi2指向一个值为105的int对象;

make_unique 函数

  • C++ 11中没有,C++ 14才有的make_unique:不支持指定的删除器语法,如果不用删除器,建议优先选择使用,更高的性能。
unique_ptr<int> p1 = make_unique<int>(100);

auto p2 = make_unique<int>(200);

unique_ptr<int> pi22(new int(105)); //前边不能简写为auto;

unique_ptr常用操作

unique_ptr不支持的操作

unique_ptr<string> ps1(new string("I Love China!"));

unique_ptr<string> ps2(ps1); //该智能指针不支持拷贝动作(定义时初始化)

unique_ptr<string> ps3 = ps1;  //该智能指针不支持拷贝动作(定义时初始化)

unique_ptr<string> ps4;
ps4 = ps1; //ps1是独占式智能指针,独占式智能指针不支持赋值操作

移动语义

unique_ptr<string> ps21(new string("I Love China!"));
unique_ptr<string> ps22 = std::move(ps21); // 移动完后,ps21 位空, ps22指向原来ps21所指

release():

  • 放弃对指针的控制权(切断了智能指针和其所指向的对象之间的联系)。
  • 返回裸指针,将该智能指针置空
    • 返回的这个裸指针我们可以手工delete来释放,也可以用来初始化另外一个智能指针,或者给另外一个智能指针赋值。
unique_ptr<string> ps31(new string("I Love China!"));
unique_ptr<string> ps32(ps31.release());
if (ps31 == nullptr){
	cout << "ps31 被置空" << endl;
}

//ps32.release(); // 导致内存泄漏
string * tempp = ps32.release(); // auto tempp = 
//delete tempp; //人工(手工)delete释放

reset()

  • reset() 不带参数情况: 释放智能指针所指向的对象,并将智能指针置空。
unique_ptr<string> ps41(new string("I Love China!"));
ps41.reset();
if (ps41 == nullptr) {
	cout << "ps41 被置空" << endl;
}
  • reset()带参数的情况:释放 智能指针所指向的对象,并让该智能指针指向新对象。
unique_ptr<string> ps42(new string("I Love China!"));
ps41.reset(ps42.release()); 
// reset释放ps41指向的对象内存,让ps41指向ps42所指向的内存,同时ps42被置空
ps41.reset(new string("I Love China!"));

= nullptr

  • 释放智能指针所指向的对象,并将智能指针置空。
unique_ptr<string> ps51(new string("I Love China!"));
ps51 = nullptr; // 释放ps51所指向的对象,并将ps51置空

指向一个数组

unique_ptr<int[]> ptrarray(new int[10]); // 注意,数组这里要跟上[]
ptrarray[0] = 12;
ptrarray[1] = 24;

//这里不要忘记A[] ,否则如果有自己的析构函数,则会报异常
unique_ptr<A[]> ptrarray1(new A[100]);

get()

  • 返回智能指针中保存的裸指针。
  • 考虑到有些函数参数需要的是内置裸指针(第三方库,咱们更改不了代码),所以引入该函数;
unique_ptr<string> ps71(new string("I Love China!"));
string* ps7 = ps71.get();
*ps7 = "This is a test!";
//delete ps7; // 不要这么干,否则产生不可预料的后果;

*解引用

  • 获取该智能指针指向的对象,可以直接操作:
unique_ptr<string> ps81(new string("I Love China!"));
ps7 = ps81.get();
unique_ptr<int> pt1(new int(100));
*pt1 = 200;

unique_ptr<int[]> pt2(new int[10]); //对于定义的内容是数组,是没有*解引用运算符的;

swap():

  • 交换两个智能指针所指向的对象。
unique_ptr<string> ps91(new string("I Love China1!"));
unique_ptr<string> ps92(new string("I Love China2!"));
std::swap(ps91, ps92);
ps91.swap(ps92);

智能指针名字作为判断条件

unique_ptr<string> ps101(new string("I Love China1!"));
if (ps101){
	//若ps101 指向一个对象,那么这个就成立
	cout << "ps101 不为空 " << endl;
}
ps101.reset();

if (ps101) {
	cout << "ps101 不为空 " << endl;
}
else{
	cout << "ps101 为空 " << endl;
}

转换成shared_ptr类型

  • 如果unique_ptr为右值,就可以将它赋值给shared_ptr
  • 因为shared_ptr包含一个显示构造函数,可用于将右值unique_ptr转换为shared_ptr, shared_ptr将接管原来归unique_ptr所拥有的对象。
auto myfunc(){
	return 	unique_ptr<string>(new string("I Love China!")); 
   // 这是个右值; (临时对象都是右值)
}

shared_ptr<string> pss1 = myfunc(); //这里会创建控制块
unique_ptr<string> ps11(new string("I Love China!"));
shared_ptr<string> pss2 = std::move(pss1); 
// 左值转右值,执行后ps11为空, pss2就是shared_ptr

返回unique_ptr

  • 虽然unique_ptr智能指针不能拷贝,但是,当这个unique_ptr将要被销毁,是可以拷贝的。最常见用法就是从函数返回一个unique_ptr。
unique_ptr<string> tuniqp(){
	//unique_ptr<string> pr(new string("I Love China!"));
	//return pr; //从函数返回一个局部的unique_ptr对象。
				//返回这种局部对象,导致系统给我们生成一个临时unique_ptr对象,调用unique_ptr的移动构造函数。
	return unique_ptr<string>(new string("I Love China!"));
}
unique_ptr<string> ps;
ps = tuniqp(); 
//可以用ps来接,则临时对象直接构造在ps里,
//如果不接,则临时对象会被释放,同时会释放掉所指向的对象的内存;

指定删除器

  • delete默认删除器;
  • a). 指定删除器
    • 格式: unique_ptr<指向的对象类型, 删除器> 智能指针变量名
  • 删除器,可调用对象,比如函数,类重载了()。
  • 我们学习过了shared_ptr 删除器,比较简单 shared_ptr<int> p(new int(), mydelete);unique_ptr删除器相对复杂一点,多了一步,先要在类型模板参数中传递进去类型名,然后在参数中再给具体的删除其函数名
  • 不同方式的删除器
typedef void(*fp)(string *); // 定义一个函数指针类型,类型名为fp
unique_ptr<string, fp> ps1(new string("I Love China!"), mydeleter);
using fp2 = void(*)(string *); // 用using定义一个函数指针类型,类型名为fp2
unique_ptr<string, fp2> ps2(new string("I Love China!"), mydeleter);
typedef decltype(mydeleter)* fp3; //这里多了一个*, 因为decltype返回的是函数类型void (string*)
							// 加* 表示函数指针类型,现在fp3 应该void *(string *);
unique_ptr<string, fp3> ps3(new string("I Love China!"), mydeleter);
unique_ptr<string, decltype(mydeleter)*> ps41(new string("I Love China!"), mydeleter);
//用lambda 表达式看看写法,lambda 表达式可以理解成带有operator()类类型对象。
//所以 decltype(mydella) = class{ ... }
auto mydella = [](string * pdel) {  // 把lambda表达式理解成一个class;
	delete pdel;
	pdel = nullptr;
	//可以打印日志
};
unique_ptr<string, decltype(mydella)> ps5(new string("I Love China!"), mydella);

指定删除器额外说明

  • shared_ptr : 就算两个shared_ptr指定的删除器不相同,只要他们所指向的对象相同,那么这两个shared_ptr也属于同一个类型。
  • 但是unique_ptr不一样,指定unique_ptr中的删除器会影响unique_ptr的类型,所以从灵活性来讲,shared_ptr设计的更灵活;
  • 咱们在讲解shared_ptr的时候,删除器不同,但指向类型一样的shared_ptr,可以放到统一个容器里,vector<shared_ptr ...>
  • unique_ptr如果删除器不同,那么就等于整个unique_ptr类型不同,这种类型不同的unique_ptr智能指针是没有办法放到同一个容器里的;

尺寸问题

  • 通常情况下,unique_ptr 尺寸跟裸指针一样:
string *p;
int ilenp = sizeof(p); //4字节

unique_ptr<string> ps31(new string("I Love China!"));
int ilen = sizeof(ps31); //4字节
  • 如果你增加了自己的删除器,则unique_ptr的尺寸可能增加,也可能不增加。
    • 如果lambda表达式这种删除器,尺寸就没变化
    • 定义一个函数作为删除器,尺寸发生变化,已经是8字节了。
  • 增加字节对效率有影响,所以自定义删除器要慎用;
  • shared_ptr, 不管你指定什么删除器, shared_ptr的尺寸(大小)都是裸指针的2倍;

智能指针总结

  • 智能指针背后的设计思想
  • 智能指针主要目的:帮助我们释放内存,以防止我们忘记释放内存时造成的内存泄漏。
  • auto_ptr为什么被废弃
    • auto_ptr : C++ 98时代的智能指针,具有 unique_ptr一部分特性; unique_ptr, shared_ptr,weak_ptr;
    • 不能在容器中保存,也不能从函数中返回auto_ptr;
auto_ptr<string> ps4(new string("I Love China"));
auto_ptr<string> ps5 = ps4;// ps5指向字符串,ps4变成空了,这可以防止ps4和ps5析构一个string两次;
//用ps4(你没有意识到ps4已经空了),代码就会崩溃;
//这个也是auto_ptr用法上的一个陷阱。

shared_ptr<string> ps6(new string("I Love China"));
shared_ptr<string> ps7 = ps6; //ps7 和ps6都有效,强引用计数为2;
unique_ptr<string> ps8(new string("I Love China"));
unique_ptr<string> ps9 = ps8; //编译出错

//虽然auto_ptr 和unique_ptr都是独占式的,但unique_ptr 这种情况,编译的时候就会报错;
//而不会默默的把ps7的所有权转移到ps8上,避免后续如果使用ps7导致程序崩溃的问题;
//当然如果你用移动语义,也能达到auto_ptr的效果:
shared_ptr<string> ps10(new string("I Love China"));
shared_ptr<string> ps11 = std::move(ps10); //运用了移动语义
  • auto_ptr被废弃的主要原因:设计的不太好,容易被误用引起潜在的程序崩溃等问题,所以C++ 11启用了unique_ptr来取代auto_ptr
  • C++ 11表示不建议再使用auto_ptr ,强烈建议大家,用unique_ptr取代;unique_ptr比auto_ptr更安全;
  • 智能指针的选择
    • a). 如果程序要使用多个指向同一个对象的指针,应该选择shared_ptr;
    • b). 如果程序不需要多个指向同一个对象的指针,应该首选unique_ptr;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值