博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ 资源管理(RAII)--智能指针
阅读量:6205 次
发布时间:2019-06-21

本文共 7899 字,大约阅读时间需要 26 分钟。

1. 智能指针(Smart Pointer)

          i. 是存储指向动态分配()对象指针的类

          ii. 在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象

          iii. RAII类模拟智能指针,见备注

2. C++11提供了以下几种智能指针,位于头文件<memory>,它们都是模板类

          i. std::auto_ptr(复制/赋值)

          ii. std::unique_ptr  c++11

          iii.std::shared_ptr  c++11

          iv.std::weak_ptr    c++11

          g++ -std=c++11 xx.cc

3. std::auto_ptr在构造时获取对某个对象的所有权(ownership),在析构时释放该对象

4. std::auto_ptr要求其对“裸”指针的完全占有性 -> 在拷贝构造或赋值操作时,会发生所有权的转移

5. 本身存在缺陷

6. std::unique_ptr是一个独享所有权的智能指针,它提供了一种严格语义上的所有权,包括:

           i. 拥有它所指向的对象

           ii. 无法进行复制、赋值操作(例题)

           iii.保存指向某个对象的指针,当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象

           iv.具有移动(std::move)语义,可做为容器元素

7. std::shared_ptr是一个引用计数智能指针,用于共享对象的所有权

           i. 引进了一个计数器shared_count,用来表示当前有多少个智能指针对象共享指针指向的内存块

           ii. 析构函数中不是直接释放指针对应的内存块,如果shared_count大于0则不释放内存只是将引用计数减1,只是计数等于0时释放内存

           iii. 复制构造与赋值操作符只是提供一般意义上的复制功能,并且将引用计数加1.

           iv. 在堆内存中只有一份申请的资源,但是有好几个对象都是指向这个内存的资源的。

           v. Shared_ptr的功能就是让不具有值语义的对象拥有值语义,假如说一个对象本身是不希望被复制的,但是要是把这个对象交给shared_ptr管理的时候,使用这个指针的时候就可以对对象进行复制,实际不是真实的对象复制,而是通过一个引用计数的方式去使用。

8. 问题:会有一个问题就是循环引用,会导致内存泄漏。

9. std::shared_ptr是强引用智能指针

10. std::weak_ptr 是弱引用智能指针

11. 强引用,只要有一个引用存在,对象就不能被释放

12. 弱引用,并不增加对象的引用计数,但它知道对象是否存在。如果存在,提升为shared_ptr成功;否则,提升失败

13. 通过weak_ptr访问对象的成员的时候,要提升为shared_ptr

 

1 auto_ptr.cc 2  3 #include
4 #include
5 6 int main(void) 7 { 8 double *pd = new double(7.77); 9 std::auto_ptr
apd(pd); //apd本身是个对象,因为它重载了星号访问运算符,所以可以加* 用。10 //或者std::auto_ptr
apd(new double(7.77));11 12 std::cout << “*apd=” << *apd <
<< apd << std::endl; //会出错,对象不能这样直接打印16 17 std::cout << “apd.get() = ” << reinterpret_cast
(apd.get()) << std::endl; 18 19 double *pd = new double(8.88);20 std::auto_ptr
apd2(pd); 21 std::cout << “pd = ” << reinterpret_cast
(pd) << std::endl;22 std::cout << “apd2.get() = ” << reinterpret_cast
(apd2.get()) << std::endl; //通过get()可以获得原生的指针所在的地址。23 24 int *pi = new int(7);25 std::auto_ptr
api1(pi);26 std::auto_ptr
api2(api1); //复制, 发生了所有权的转移。首先把api1裸指针所指向的值交给了api2, 同时又把api1所指向的值设为了空。相当于api1对pi的所有权完全交给了api2。发生所有权的转移,与常规的认识矛盾。本身有缺陷,不推荐使用。27 // std::auto_ptr要求其对“裸”指针的完全占有性在拷贝构造或赋值操作时,会发生所有权的转移28 29 std::cout << “*api1= ” << *api1 <
<< *api2 <
1 unique_ptr.cc 2  3 #include
4 #include
5 #include
6 7 8 std::unique_ptr
getVal() //这里返回一个unique_ptr对象,这个对象是个右值。 9 { 10 std::unique_ptr
up(new int(66));11 return up;12 }13 14 int main(void)15 {16 // 无法进行复制、赋值操作17 std::unique_ptr
ap(new int(99));18 //std::unique_ptr
one(ap); //编译出错,不能够进行复制。19 20 std::unique_ptr
two;21 //two = ap; //编译出错,不能进行赋值。22 23 std::cout << “*ap = ” << *ap << std::endl;24 std::cout << “ap.get() = ” << reinterpret_cast
(ap.get()) << std::endl; //获取指针的值25 26 //可以进行移动构造和移动赋值操作27 std::unique_ptr
up = getVal(); //getVal()函数返回一个右值,这个右值会优先绑定到右值引用上去。unique_ptr是具有移动语义的,意思就是说它提供了一个移动构造函数和一个移动赋值函数。而这里就优先调用了移动赋值函数。并没有调用复制构造函数。28 std::cout << “*up = ” << *up << std::endl;29 30 31 //实际上上面的操作有点类似于如下操作32 Unique_ptr
up(int new int(99));33 Unique_ptr
uPtr2 = std::move(up); //这里是显式的所有权转移。把up所指的内存转给uPtr2了,而up不再拥有该内存。34 35 36 37 //可以作为容器的元素(就是因为具有移动语义)38 std::unique_ptr
sp(new int(55)); //sp现在是一个左值,就要绑定到复制构造函数上面去,因为复制构造函数的参数是一个左值引用。39 std::vector
vec;40 //vec.push_back(sp); //会出错,因为会调用复制构造函数41 vec.puch_back(std::move(sp)); //将左值转成右值引用,这时就会调用 移动构造函数,而不是 复制构造函数。42 std::cout << *vec[0] << std::endl; //打印刚添加的值。43 44 return 0;45 }
1 Shared_ptr.cc 2  3     #include
4 #include
5 6 class Child; 7 class Parent; 8 9 typedef std::shared_ptr
Child_ptr;10 typedef std::shared_ptr
Parent_ptr;11 12 class Child13 {14 public:15 Child()16 {17 std::cout << “Child()” << std::endl;18 }19 ~Child()20 {21 std::cout << “~Child()” << std::endl;22 }23 //private: 24 Parent_ptr parent_;25 };26 27 class Parent28 {29 public:30 Parent()31 { 32 std::cout << “Parent()” << std::endl;33 }34 ~Parent()35 { 36 std::cout << “~Parent()” << std::endl;37 }38 39 //private:40 Child_ptr child_;41 };42 43 int main(void)44 {45 Parent_ptr parent(new Parent); //交给shared_ptr进行管理46 Child_ptr child(new Child); 47 48 std::cout << “parent’s count = ” << parent.use_count() << std::endl;49 std::cout << “child’s count = ” << child.use_count() << std::endl;50 51 std::cout << “进行复制之后:” << std::endl;52 parent->child_ = child; //shared_ptr复制操作53 std::cout << “child’s count = ” << child.use_count() << std::endl; //打印出引用计数为2.54 child->parent_ = parent;55 std::cout << “parent’s count = ” << parent.use_count() << std::endl; //打印出引用计数为2.56 57 return 0;58 }59 //因为相互引用,当程序结束时,引用计数都减一,都成为1。内存中还有这两个对象的存在,就不会调用析构函数。这样就带来了内存泄漏,是循环引用存在的问题。

 

1 weak_ptr1.cc 2  3     #include
4 #include
5 6 class Child; 7 class Parent; 8 9 typedef std::shared_ptr
Child_ptr;10 typedef std::shared_ptr
Parent_ptr;11 12 class Child13 {14 public:15 Child()16 {17 std::cout << “Child()” << std::endl;18 }19 ~Child()20 {21 std::cout << “~Child()” << std::endl;22 }23 //private: 24 Parent_ptr parent_;25 };26 27 class Parent28 {29 public:30 Parent()31 { 32 std::cout << “Parent()” << std::endl;33 }34 ~Parent()35 { 36 std::cout << “~Parent()” << std::endl;37 }38 39 std::weak_ptr
child_; //弱引用40 };41 42 int main(void)43 {44 Parent_ptr parent(new Parent); //交给shared_ptr进行管理45 Child_ptr child(new Child); 46 47 std::cout << “parent’s count = ” << parent.use_count() << std::endl;48 std::cout << “child’s count = ” << child.use_count() << std::endl;49 50 std::cout << “进行复制之后:” << std::endl;51 parent->child_ = child; //child_是weak_ptr,引用计数并没有加152 std::cout << “child’s count = ” << child.use_count() << std::endl; //打印出引用计数为2.53 child->parent_ = parent;54 std::cout << “parent’s count = ” << parent.use_count() << std::endl; //打印出引用计数为2.55 56 return 0;57 }58 //因为使用的是弱引用,复制的时候引用计数不会加1. 程序结束时会调用析构函数。
1 Weak_ptr.cc  2 #include
3 #include
4 5 class X 6 { 7 public: 8 X() {std::cout << “X()” << std::endl;} 9 ~ X() {std::cout << “~X()” << std::endl;}10 11 void fun()12 {13 std::cout << “fun()” << std::endl;14 }15 };16 17 int main(void)18 {19 std::weak_ptr
p;20 {21 std::shared_ptr
p2(new X); //所有new出来的东西都放到这个栈对象p2里面,因为当这个语句块结束的时候p2会调用析构函数,我们在析构函数中加上delete来释放托管过来的指针。22 std::cout << “p2’s count = ” << p2.use_count() <
<< p2.use_count() <
p3 = p.lock(); //lock()函数就是用来提升weak_ptr为shared_ptr的函数。29 30 if(p3) //提升成功31 {32 p3->fun();33 std::cout << “p3’s count = ” << p3.use_count() <
p4 = p.lock(); 44 if(p4) //提升成功45 {46 P4->fun();47 std::cout << “p4’s count = ” << p4.use_count() <
*pthis = new std::shared_ptr
(new X);57 //上述方式就是生成堆对象,不推荐这么做。而且这时候只能通过显示调用delete函数,这样就跟我们的初衷不符。58 59 return 0;60 }

 

转载于:https://www.cnblogs.com/jianhui-Ethan/p/4665550.html

你可能感兴趣的文章
eclipes快捷键
查看>>
强大的django-debug-toolbar,django项目性能分析工具
查看>>
VueJs学习入门指引
查看>>
Python中集合(set)的操作及一些比较常见的用法
查看>>
Mysql limit 子查询
查看>>
海量数据库的查询优化及分页算法方案(一)
查看>>
scheme 学习:红黑树
查看>>
入库成本与目标成本对比报表中我学到的东西
查看>>
网页字体设置你了解吗?
查看>>
处理测试环境硬盘爆满
查看>>
DEV GridView嵌套
查看>>
例子:好友列表选中效果
查看>>
Linux下如何自己编译源代码(制作成可以安装的.deb文件)
查看>>
不要手贱自己去通过Javascript画html界面
查看>>
ubuntu 跟xshell的问题
查看>>
取重复记录最大的id列表
查看>>
LR+Jenkins实践思路
查看>>
ie8 ajaxSubmit 上传文件提示下载
查看>>
Web UI 设计(网页设计)命名规范
查看>>
只能输入正整数 以及常用的正则表达式
查看>>