一、shared_ptr学习

1.shared_ptr和weak_ptr 基础概念

  • shared_ptr与weak_ptr智能指针均是C++ RAII的一种应用,可用于动态资源管理
  • shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。
  • shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作。
  • weak_ptr用于解决“引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器

2.shared_ptr的基本操作

  1. #include <memory>
  2. #include <iostream>
  3. struct Foo {
  4. Foo() { std::cout << "Foo...\n"; }
  5. ~Foo() { std::cout << "~Foo...\n"; }
  6. };
  7. struct D {
  8. //删除p所指向的Foo对象
  9. void operator()(Foo* p) const {
  10. std::cout << "Call delete for Foo object...\n";
  11. delete p;
  12. }
  13. };
  14. int main()
  15. {
  16. // constructor with no managed object
  17. std::shared_ptr<Foo> sh1;
  18. // constructor with object
  19. std::shared_ptr<Foo> sh2(new Foo);
  20. std::shared_ptr<Foo> sh3(sh2);
  21. std::cout << sh2.use_count() << '\n';
  22. std::cout << sh3.use_count() << '\n';
  23. //constructor with object and deleter
  24. std::shared_ptr<Foo> sh4(new Foo, D());
  25. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

构造方法: 
1.通过make_shared函数构造 
auto s_s = make_shared(“hello”);

2.通过原生指针构造 
int* pNode = new int(5); 
shared_ptr s_int(pNode); 
//获取原生指针 
int* pOrg = s_int.get();

3.通过赋值函数构造shared_ptr

4.重载的operator->, operator *,以及其他辅助操作如unique()、use_count(), get()等成员方法。

3 实验智能指针引用计数,增加和减少的规律

实验的主要内容有: 
1.shared_ptr变量在生命周期中销毁后,引用计数是否减1? 
2.shared_ptr作为函数参数,分为传值和传引用,引用计数如何变化? 
2.函数返回值为shared_ptr类型时,引用计数是否会变化?

带着这几个问题,我们来看下代码.

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. void Func1(shared_ptr<int> a)
  5. {
  6. cout<<"Enter Func1"<<endl;
  7. cout<<"Ref count: "<<a.use_count()<<endl;
  8. cout<<"Leave Func1"<<endl;
  9. }
  10. shared_ptr<int> Func2(shared_ptr<int>& a)
  11. {
  12. cout<<"Enter Func2"<<endl;
  13. cout<<"Ref count: "<<a.use_count()<<endl;
  14. cout<<"Leave Func2"<<endl;
  15. return a;
  16. }
  17. int main()
  18. {
  19. //构造一个指向int类型对象的指针aObj1,引用计数+1
  20. shared_ptr<int> aObj1(new int(10));
  21. cout<<"Ref count: "<<aObj1.use_count()<<endl;
  22. {
  23. //同aObj1,不过由于生存周期在括号内,所以aObj2会被销毁
  24. shared_ptr<int> aObj2 = aObj1;
  25. cout<<"Ref count: "<<aObj2.use_count()<<endl;//引用计数-1
  26. }
  27. //在调用函数时,参数为shared_ptr类型,参数为传值类型,智能指针引用计数+1
  28. Func1(aObj1);
  29. //在调用函数时,参数为shared_ptr类型,参数为传引用类型,智能指针引用计数不变
  30. Func2(aObj1);
  31. shared_ptr<int> aObj3 = Func2(aObj1);//引用计数+1
  32. cout<<"Ref count:"<<aObj3.use_count()<<endl;
  33. return 0;
  34. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

运行结果如下: 

有效的掌握好智能指针的引用计数的变化规律,才能把程序写的更好.

4. shared_ptr的应用场景以及使用注意事项

4.1 对象之间“共享数据”,对象创建与销毁“分离” 
4.2 放入容器中的动态对象,使用shared_ptr包装,比unique_ptr更合适 
4.3 管理“动态数组”时,需要制定Deleter以使用delete[]操作符销毁内存,因为shared_ptr并没有针对数组的特化版本(unique_ptr有针对数组的特化版本)

5.shared_ptr的线程安全问题

  1. 同一个shared_ptr被多个线程读,是线程安全的;
  2. 同一个shared_ptr被多个线程写,不是 线程安全的;
  3. 共享引用计数的不同的shared_ptr被多个线程写,是线程安全的。 
    对于第三点,我们一般采用: 
    对于线程中传入的外部shared_ptr对象,在线程内部进行一次新的构造,例如: sharedptr AObjTmp = outerSharedptrObj;

二、weak_ptr学习

我们先搞清楚,weak_ptr为什么出现,或者说它是为了解决什么问题而存在的(存在即合理),哈哈

  1. class Parent
  2. {
  3. public:
  4. shared_ptr<Child> child;
  5. };
  6. class Child
  7. {
  8. public:
  9. shared_ptr<Parent> parent;
  10. };
  11. shared_ptr<Parent> pA(new Parent);
  12. shared_ptr<Child> pB(new Child);
  13. pA->child = pB;
  14. pB->parent = pA;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在Parent类中存储了指向Child类对象的智能指针成员变量,而在Child类中也存储了指向Parent类对象的智能指针成员变量,如此就会造成环形引用,这个成因在C++中很好解释.

要解决环形引用的问题,没有特别好的办法,一般都是在可能出现环形引用的地方使用weak_ptr来代替shared_ptr。说到了weak_ptr,那下面就接着总结weak_ptr吧。

下面我们来一起学习下weak_ptr这个东东

weak_ptr指向shared_ptr指针指向的对象的内存,却并不拥有该内存。 
但是,使用weak_ptr成员lock,则可返回其指向内存的一个shared_ptr对象,且在所指对象内存已经无效时,返回指针空值(nullptr)。由于weak_ptr是指向shared_ptr所指向的内存的,所以,weak_ptr并不能独立存在。

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. void Check(weak_ptr<int> &wp)
  5. {
  6. shared_ptr<int> sp = wp.lock(); // 重新获得shared_ptr对象
  7. if (sp != nullptr)
  8. {
  9. cout << "The value is " << *sp << endl;
  10. }
  11. else
  12. {
  13. cout << "Pointer is invalid." << endl;
  14. }
  15. }
  16. int main()
  17. {
  18. shared_ptr<int> sp1(new int(10));
  19. shared_ptr<int> sp2 = sp1;
  20. weak_ptr<int> wp = sp1; // 指向sp1所指向的内存
  21. cout << *sp1 << endl;
  22. cout << *sp2 << endl;
  23. Check(wp);
  24. sp1.reset();
  25. cout << *sp2 << endl;
  26. Check(wp);
  27. sp2.reset();
  28. Check(wp);
  29. system("pause");
  30. return 0;
  31. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

学习编程最好的方式就是一步步的跟踪去调试. 
借鉴上面的代码,我们在使用weak_ptr时也要当心,时刻需要判断weak_ptr对应的shared_ptr是否为空,weak_ptr并不会增加shared_ptr的引用计数.

另附一篇地址,讲解为何不同的shared_ptr对象可以被多线程同时修改(即使这些shared_ptr对象管理着同一个对象的指针)

https://blog.csdn.net/jiangfuqiang/article/details/8292906

C++11学习之share_ptr和weak_ptr的更多相关文章

  1. C++11智能指针 share_ptr,unique_ptr,weak_ptr用法

    0x01  智能指针简介  所谓智能指针(smart pointer)就是智能/自动化的管理指针所指向的动态资源的释放.它是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动 ...

  2. C++11 学习笔记 std::function和bind绑定器

    C++11 学习笔记 std::function和bind绑定器 一.std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法 ...

  3. C++11学习笔记

    C++11 1.long long新类型 2.列表初始化 int t=0; int t={0}; int t(0); int t{0}; 注意:如果我们使用列表初始化有丢失信息的风险,则编译器报错 l ...

  4. C++ 11 学习1:类型自动推导 auto和decltype

    Cocos 3.x 用了大量的C++ 11 的东西,所以作为一个C++忠实粉丝,有必要对C++ 11进行一个系统的学习. 使用C++11之前,一定要注意自己使用的编译器对C++11的支持情况,有些编译 ...

  5. C++ 11 创建和使用共享 weak_ptr

    1.为什么需要weak_ptr? 在正式介绍weak_ptr之前,我们先来回忆一下shared_ptr的一些知识.我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以 ...

  6. C++11学习

    转自: https://www.cnblogs.com/llguanli/p/8732481.html Boost教程: http://zh.highscore.de/cpp/boost/ 本章目的: ...

  7. Linux0.11学习

    Linux 0.11虽然不是什么“珠穆朗玛峰”,但它肯定还是“华山”或“泰山”.虽然有路但你还是需要最基本的努力和花费一定的代价才能“攀登”上去.1. PC兼容机硬件工作原理(比如8259A,8253 ...

  8. C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)

    因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...

  9. C++ 11学习(1):lambda表达式

    转载请注明,来自:http://blog.csdn.net/skymanwu #include <iostream> #include <vector> #include &l ...

随机推荐

  1. Derby的jar说明

    Derby的jar说明 Derby的下载后,解压发现lib中有很多jar包,下面说明一下每个jar包的用途: 引擎库 derby.jar是引擎库,必须的 For embedded databases. ...

  2. ubuntu 修改 ls 下的目录颜色

    ubuntu 下, ls 显示的目录的颜色,怎么说呢,看起来太费劲了. 于是想着修改成容易识别的颜色. 于是搜索了一下. 这里列举三个搜到的教程吧. 简单说我按这上面的方法做了,然后都失败了. 1.  ...

  3. EntityManager对象管理

    根据EntityManager对象的管理方式,可以有以下两种类型: — 容器托管的(container-managed)EntityManager对象 容器托管的EntityManager对象最简单, ...

  4. Java代码在本地运行没有问题。上传到阿里云服务器后。出现了中文乱码解决

    java -Dfile.encoding=UTF-8 -jar project.jar

  5. HDU 5656 ——CA Loves GCD——————【dp】

    CA Loves GCD Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)To ...

  6. Codeforces 809D. Hitchhiking in the Baltic States

    Description 给出 \(n\) 个数 \(a_i\),每一个数有一个取值 \([l_i,r_i]\) ,你来确定每一个数,使得 \(LIS\) 最大 题面 Solution 按照平时做法,设 ...

  7. 【转】mvc

    又看到有人在问三层架构和MVC的关系,感觉这种问题有点教条化了.因为它们都在逻辑上将应用程序划为三块,凑了一个数字3,就有人非要把它们联系到一起了. 这两个东西我接触有几年了,有一点体会,表达一下: ...

  8. easyui焦点离开事件的解决方案

  9. [android] 练习viewpagerindicator的使用(二)

    主要还是想实现滑动的tab切换效果 MainActivity.java package com.example.csdn; import com.viewpagerindicator.TabPageI ...

  10. [javaEE] 开源数据库连接池

    一些开源组织提供了数据源的独立实现: DBCP数据库连接池 C3P0数据库连接池 Apache Tomcat内置的连接池 DBCP连接池 apache提供的连接池实现,需要导入common-dbcp. ...