栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Th5.7:智能指针(unique

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Th5.7:智能指针(unique

本小节学习的知识点分别是智能指针(unique_ptr)之详述、删除器、尺寸以及智能指针总结。

今天总结的知识分为以下4个大点:

(1)返回unique_ptr
(2)指定删除器
(3)尺寸问题
(4)智能指针总结
    (4.1)智能指针背后的设计思想
    (4.2)auto_ptr(C++98)为什么被废弃
    (4.3)智能指针的选择问题

(1)返回unique_ptr:

        我们知道,unique_ptr是一种独占式的智能指针,不允许拷贝/赋值给其他unique_ptr指针!但是,当unique_ptr作为一个临时对象指针时,就可以做拷贝和赋值操作了!

auto mfunc(int val)  {
	return unique_ptr(new int(val));//返回unique_ptr这个临时指针对象
}
unique_ptr ptr1(unique_ptr(new int()));//临时的unique_ptr对象作拷贝操作✓!
unique_ptr ptr2 = mfunc(188);//临时的unique_ptr对象作赋值操作✓!

(以后coding时看到别人写这种返回unique_ptr指针的用法千万不要以为是错的!)

(2)指定删除器:

        指定unique_ptr智能指针的删除器的格式:

unique_ptr<所指向的varType,deleterTypeName> 智能指针变量名;

        <内>,先指定unique_ptr指针所指向的对象的类型名,再指定删除器的类型名(注意:这里的类型名,就是函数类型的删除器,你要用typedef来定义一个指向该类型函数的一个函数指针类型,然后再将该函数指针类型传入unique_ptr指针中!)

例子代码:

void mydeleter(int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
}
//a)函数类型的删除器(用法介绍):
//a.1):
typedef void (*funcPointer)(int*);
//定义了一种函数指针类型funcPointer,这种类型的指针是指向一个函数返回值为void,参数类型为int*的函数的!
unique_ptr ptr1(new int(18), mydeleter);
//a.2):
using fp = void(*)(int*);
//定义了一种函数指针类型fp,这种类型的指针是指向一个函数返回值为void,参数类型为int*的函数的!
unique_ptr2 ptr2(new int(28), mydeleter);
//a.3):
typedef decltype(mydeleter)* fpp;
//因为decltype关键字返回的是一种函数类型void (int*)
//加上*号就让fpp == void (*)(int*) 这种函数指针类型
//定义了一种函数指针类型fpp,这种类型的指针是指向一个函数返回值为void,参数类型为int*的函数的!
unique_ptr ptr3(new int(38), mydeleter);
//a.4):
unique_ptr ptr4(new int(48), mydeleter);
//a.5):
//用lambda表达式(可以理解为一个类class)来do
auto mydeleter2 = [](int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
};
unique_ptr ptr5(new int(58), mydeleter2);

运行结果都是:

指定删除器的补充说明:

        在之前的学习中,我们都知道,即便2个shared_ptr的指定删除器类型名不同,但是varType一样的话,那么这2个shared_ptr也会算作是同一类型的指针!

比如:

void myIntDelete(int* pt) {
	delete pt;
	pt = nullptr;
}
shared_ptr sp1(new int(), default_delete());
shared_ptr sp2(new int(),myIntDelete);
可认为sp1和sp2是同一种类型的shared_ptr指针

        但是,unique_ptr则与shared_ptr不同!因为对于unique_ptr模板类指针来说,其所指向对象的类型T和所使用的删除器deleter都属于该类指针的类型名!

比如:

typedef void (*funcPointer)(int*);
unique_ptr unptr1(new int(18), mydeleter);
//用lambda表达式(可以理解为一个类class)来do
auto mydeleter2 = [](int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
};
unique_ptr unptr2(new int(28), mydeleter2);
不可认为unptr1和unptr2是同一种类型的unique_ptr指针

 (3)尺寸问题:

        unique_ptr智能指针占用的内存一般都会与裸指针所占用的内存是保持一致的!

int a = 1;
int* pt = &a;
int len1 = sizeof(pt);//8字节 与int*的裸指针一样大!
unique_ptr unptr(new int(1));
int len2 = sizeof(unptr);//8字节 与int*的裸指针一样大!

       特殊case:当unique_ptr智能指针带有自己指定的删除器deleter时,其所占据的内存空间就和裸指针的就有可能不一致了!

        与对应裸指针所占据的内存不一致的case:

void mydeleter(int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
}
typedef void (*fp)(int*);
unique_ptr unptr2(new int(2), mydeleter);
int len3 = sizeof(unptr2);//16字节 与int*的裸指针不一样大!

        指定了删除器deleter后与对应裸指针所占据的内存还保持一致的case:(使用lambda表达式作为unique_ptr指针的deleter)

auto mydeleter2 = [](int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
};
unique_ptr unptr(new int(123), mydeleter2);
int len = sizeof(unptr);//8字节 与int*的裸指针一样大!

        但是对于shared_ptr这种智能指针而言,不论你指定何种deleter,shared_ptr的尺寸(所占据的内存空间的大小)都是裸指针的2倍!

比如:

auto mydeleter2 = [](int* pval) {
	delete pval;
	pval = nullptr;
	cout << "调用了自己指定的函数类型的删除器!" << endl;
};
shared_ptr sp1(new int(1), mydeleter2);
int len1 = sizeof(sp1); 
shared_ptr sp2(new int(2), default_delete());
int len2 = sizeof(sp1);
shared_ptr sp3(new int(3));
int len3 = sizeof(sp3);
cout << "len1 = " << len1 <<" len2 = "<< len2 << " len3 = " << len3 << endl;
//result: len1 == len2 == len3 == 16字节 == 裸指针int* 所占据的内存大小8字节的2倍 

        从上述代码的运行结果可见,对于unique_ptr智能指针,自己指定deleter时,又可能会导致增加字节数的情况发生,而字节数的增加又会影响你代码的效率!

        结论:对于unique_ptr智能指针自定义的deleter请务必要谨慎使用!

(4)智能指针总结:
    (4.1)智能指针背后的设计思想:

        我们此前详细地学习了很多关于几种智能指针的用法。但是我们务必要清楚,到底为什么要引入智能指针呢?(面试考)这就是问你智能指针背后都思想到底是啥呢?

        答:为了防止我们程序员忘记释放内存,从而导致内存泄露leakage问题,进而导致你的代码崩溃,so出现了智能指针!
    (4.2)auto_ptr(C++98)为什么被废弃:

auto_ptr和unique_ptr一样,也是独占式的智能指针,但是C++11已经强烈表示不建议再使用这种不好的老智能指针了。原因如下:

        reason1:auto不能保存到容器(比如vector/string)中

        reason2:也不能从函数中返回auto_ptr指针

        reason3:用法有缺陷(陷阱)

例子代码:

auto_ptr ptr1(new int(1));
auto_ptr ptr2(ptr1);

调试运行结果:

        运行auto_ptr ptr2(ptr1);这行代码之前的调试结果:

        运行auto_ptr ptr2(ptr1);这行代码之后的调试结果:    

 

        从运行结果可见,一旦你将一个auto_ptr赋值/拷贝给另一个auto_ptr时,就会出现原auto_ptr被置为nullptr的情况!这样你在后序coding时若不注意就一定会写出错误的代码!这即是auto_ptr被C++11的新标准弃用的一个重要reason!

        (4.3)智能指针的选择问题:

 a)当你的程序中需要使用多个指向同一个对象的指针,则首选shared_ptr;

 b)当你的程序中只需要使用指向一个对象的指针,则首选unique_ptr;(实际开发中,常用)

       

        好,以上就是我总结的关于所有的智能指针知识点的笔记。希望你能读懂并且消化完,也希望自己能牢记这些小小的细节知识点,加油吧,我们都在coding的路上~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/656677.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号