关于shared_ptr临时变量是否会增加引用计数的问题

qq_35852516 2018-05-17 06:01:42
void process(std::shared_ptr<int> ptr)
{
std::cout << "inside the process function:" << ptr.use_count() <<endl;
std::cout << "unique? " << ptr.unique() << endl;
}

process(shared_ptr<int> (new int(100)));

shared_ptr<int> (new int(100))作为临时变量应该是在process调用结束后才被析构的,而ptr的初始化使用了拷贝构造函数,理应使引用计数加一,但为什么在有两个shared_ptr(ptr和临时变量)指向同一片内存区域时,输出为:
inside the process function:1
unique? 1
萌新百思不得其解。

作为参照
shared_ptr<int> p1(new int(100));
process(p1);
此时输出为
inside the process function:2
unique? 0
...全文
1123 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
donjin9 2018-05-18
  • 打赏
  • 举报
回复
接分,试了下,没发生拷贝构造。
qq_35852516 2018-05-18
  • 打赏
  • 举报
回复
LZ想了一下,应该是因为调用拷贝构造函数将临时变量传给ptr时,由于拷贝构造函数是传引用的形式,所以ptr实际是临时变量的别名,故不增加计数。
Saleayas 2018-05-18
  • 打赏
  • 举报
回复
右值引用执行的是移动构造。就算没有移动构造,编译器会优化的。
qq_35852516 2018-05-17
  • 打赏
  • 举报
回复
求解
C++智能指针:shared_ptr⽤法详解 C++智能指针:shared_ptr⽤法详解 shared_ptr是C++11⾥的新特性,其包装了new操作符在堆上分配的动态对象。如: shared_ptr sp1(new int(100)); //相当于 //int *sp1=new int(100); //auto sp1=make_shared(100); 它与普通指针相⽐,最⼤的不同点就是shared_ptr是⼀个类,当对象⽣命周期结束时,⾃动调⽤其析构函数,释放内存。⽽不再需要程 序员显⽰地调⽤delete关键字。 同时,shared_ptr重载了"*"和"->"操作符以模仿原始指针的⾏为,并且提供了显⽰bool类型转换以判断指针的有效性。 shared_ptr sp1(new int(100)); assert(sp1); *sp1=200; shared_ptr sp2(new string("Hello")); assert(sp2->size()==5); 我们还可以使⽤shared_ptr的成员函数get()获取原始指针 shared_ptr sp1(new int(100)); int *Int_ptr=sp1.get(); shared_ptr⾥的reset()函数 shared_ptr⾥有个成员函数use_count(),⽤于返回该对象的引⽤计数shared_ptr sp1(new int(100)); cout<<"当前计数: "<计数: "<计数: "<计数: "<shared_ptr对象调⽤reset()函数时,它的作⽤时将引⽤计数减⼀,调⽤本⾝的对象的引⽤计数变为0. shared_ptr sp1(new int(100)); cout<<"当前计数: "<计数: "<计数: "<计数: "<计数为1,sp1的计数为0. cout << "sp2当前计数: " << sp2.use_count() << endl; cout << "sp1当前计数: " << sp2.use_count() << endl; 上⾯代码运⾏后,sp2的计数为0,sp1的计数为1。若将sp2.reset()换位sp1.reset(),则sp2的计数为1,sp1的计数为0。 在每次对shared_ptr进⾏拷贝或者赋值的时候,都使计数加1。 ⼯⼚函数 每次使⽤shared_ptr都需要显⽰的使⽤new关键字创建⼀个对象。固std库提供了⼀个⼯⼚函数make_shared()。 ⽤法: auto sp1=make_shared(100); //相当于 shared_ptr sp1(new int(100)); make_shared是⼀个泛型,<>⾥⾯为数据类型,()对应着new()⾥的东西,其返回值是⼀个shared_ptr类型的变量。 定制删除器 shared_ptr的构造函数可有多个参数,其中有⼀个是shared_ptr(Y *p,D d),第⼀个参数是要被管理的指针,它的含义与其构造函数的参 数相同。⽽第⼆个参数则告诉shared_ptr在析构时不要使⽤delete来操作指针p,⽽要⽤d来操作,即把delete p 换成d(p)。因此,我们 就可以⾃⼰制作⼀个删除器 如:对于传统的struct FILE的C⽂件操作,需要 FILE *fp=fopen("./1.txt","r"); //... //... fclose(fp); 若⽤shared_ptr,则可以这样做: shared_ptr fp(fopen("./1.txt","r"), fclose); 离开作⽤域时,shared_ptr⾃动调⽤fclose()函数关闭⽂件。
84、智能指针的原理、常⽤的智能指针及实现 、智能指针的原理、常⽤的智能指针及实现 原理 智能指针是⼀个类,⽤来存储指向动态分配对象的指针,负责⾃动释放动态分配的对象,防⽌堆内存泄漏。动态分配的资源,交给⼀个类对 象去管理,当类对象声明周期结束时,⾃动调⽤析构函数释放资源 常⽤的智能指针 (1) shared_ptr 实现原理:采⽤引⽤计数器的⽅法,允许多个智能指针指向同⼀个对象,每当多⼀个指针指向该对象时,指向该对象的所有智能指针内部的 引⽤计数加1,每当减少⼀个智能指针指向对象时,引⽤计数 减1,当计数为0的时候⾃动的释放动态分配的资源。 a.智能指针将⼀个计数器与类指向的对象相关联,引⽤计数器跟踪共有多少个类对象共享同⼀指针 b.每次创建类的新对象时,初始化指针并将引⽤计数置为1 c.当对象作为另⼀对象的副本⽽创建时,拷贝构造函数拷贝指针并增加与之相应的引⽤计数 d.对⼀个对象进⾏赋值时,赋值操作符减少左操作数所指对象的引⽤计数(如果引⽤计数为减⾄0, 则删除对象),并增加右操作数所指对 象的引⽤计数 e.调⽤析构函数时,构造函数减少引⽤计数(如果引⽤计数减⾄0,则删除基础对象) (2) unique_ptr unique_ptr采⽤的是独享所有权语义,⼀个⾮空的unique_ptr总是拥有它所指向的资源。转移⼀个 unique_ptr把所有权全部从源指针转 移给⽬标指针,源指针被置空;所以unique_ptr不⽀持普通的 拷贝和赋值操作,不能⽤在STL标准容器中;局部变量的返回值除外(因为编 译器知道要返回的对象将 要被销毁);如果你拷贝⼀个unique_ptr,那么拷贝结束后,这两个unique_ptr指向相同的资源, 造成在结束 时对同⼀内存指针多次释放⽽导致程序崩溃。 (3) weak_ptr weak_ptr:弱引⽤。 引⽤计数有⼀个问题就是互相引⽤形成环(环形引⽤),这样两个指针指向的内 存都⽆法释放。需要使⽤weak_ptr打 破环形引⽤。weak_ptr是⼀个弱引⽤,它是为了配合shared_ptr ⽽引⼊的⼀种智能指针,它指向⼀个由shared_ptr管理的对象⽽不影响所指 对象的⽣命周期,也就是 说,它只引⽤,不计数。如果⼀块内存被shared_ptr和weak_ptr同时引⽤,当所有shared_ptr析构了之 后,不管还 有没有weak_ptr引⽤该内存,内存也被释放。所以weak_ptr不保证它指向的内存⼀定是 有效的,在使⽤之前使⽤函数lock()检查weak_ptr 是否为空指针。 (4) auto_ptr 主要是为了解决"有异常抛出时发⽣内存泄漏"的问题 。因为发⽣异常⽽⽆法正常释放内存。 auto_ptr有拷贝语义,拷贝后源对象变得⽆效,这可能引发很严重的问题;⽽unique_ptr则⽆拷贝语 义,但提供了移动语义,这样的错误不 再可能发⽣,因为很明显必须使⽤std::move()进⾏转移。 auto_ptr不⽀持拷贝和赋值操作,不能⽤在STL标准容器中。STL容器中的元素经常要⽀持拷贝、赋值操 作,在这过程中auto_ptr传递所有 权,所以不能在STL中使⽤。
学习并掌握C++2.0(11+14+17+20)的新特性,学习线程及线程池的应用 ---------------------------------------------------给小白学员的3年学习路径及计划技术方面分三块:1.纯开发技术方向2.音视频流媒体专业方向3.项目实战---------------------------------------------------1.纯开发技术方向(1) C++必须要过硬(至少学10本经典好书)(2) 系统级编程(Windows、Linux),必须特别熟练系统API,灵活运用(3) 框架与工具(Qt、MFC):必须精通其中一种。(4) 架构与设计模式:需要提升一个高度,不再是简单的编码,而是思维模式。(5) 驱动级别(如果有兴趣,可以深入到驱动级:包括Windows、Linux)(6) 最好学习点Java+Html+javascript等WEB技术。2.音视频流媒体专业方向(1) 音视频流媒体基础理论:   必须认真学,否则看代码就是看天书(2) 编解码方向:精通h.264,h.265(hevc), 包括理论和各个开源库(ffmpeg,libx264,libx265,...)。(3) 直播方向:  精通各种直播协议(rtsp,rtmp,hls,http-flv,...), 钻研各个开源库(live555,darwin,srs,zlmediakit,crtmpserver,...)(4) 视频监控:  理论+开源库(onvif+281818)(EasyMonitor、iSpy、ZoneMinder(web)、...) 3.项目实战(1) Qt项目:  至少要亲手练习10个实战项目(网络服务器、多线程、数据库、图像处理、多人聊天、等等)(2)音视频项目:包括编解码、视频监控、直播等各个方向,都需要亲手实战项目,包括视频服务器、后台管理系统、前端播放器(多端)---------------------------------------------------  第1章 C++11新特性 41). nullptr关键字与新语法 42). auto和decltype类型推导 6 auto讲解 6 auto示例 7 decltype 83). for区间迭代 94). 初始化列表 105). 模板增强 11外部模板 11类型别名模板 12默认模板参数 126). 构造函数 13委托构造 13继承构造 147). Lambda 表达式 158). 新增容器 20std::array 20std::forward_list 21无序容器 22元组 std::tuple 239). 正则表达式 2610). 语言级线程支持 28多线程库简介 2811). 右值引用和move语义 31右值引用和move语义 32转移左值 3412). constexpr 35第2章 C++14新特性 36Lambda 函数 36类型推导 37返回值类型推导(Return type deduction) 37泛型lambda 39[[弃用的]]  [[deprecated]]属性 40二进制数字和数字分隔符 41第3章 C++17新特性 42安装GCC10.2 42安装msys2-x86_64-20200720 42更新镜像 42更新软件库 43安装 MinGW64 等必要的软件 43环境变量Path 43编译命令 43constexpr 44typename 45折叠表达式 47结构化绑定 48条件分支语句初始化 49聚合初始化 50嵌套命名空间 52lambda表达式捕获*this的值 53改写/继承构造函数 54用auto作为非类型模板参数 55__has_include 56fallthrough 57nodiscard 57maybe_unused 58第4章 C++20新特性 59编译命令 59concept 59typename 60explicit 61constinit 62位域变量的默认成员初始化 62指定初始化 63基于范围的for循环初始化 64放宽基于范围的for循环,新增自定义范围方法 65嵌套内联命名空间 66允许用圆括弧的值进行聚合初始化 67unicode字符串字面量 68允许转换成未知边界的数组 68likely和unlikely 69第5章 C++2.0(11/14/17/20)总结与分析 705.1 C语言与C++ 715.2 语言可用性的强化 725.2.1 常量 725.2.2 变量及其初始化 735.2.3 类型推导 745.2.4 控制流 765.2.5 模板 775.2.6 面向对象 815.3 语言运行期的强化 835.3.1 Lambda 表达式 835.3.2 右值引用 865.4 容器 885.4.1 线性容器 885.4.2 无序容器 895.4.3 元组 895.5 智能指针与内存管理 905.5.1 RAII 与引用计数 905.5.2 std::shared_ptr 905.5.3 std::unique_ptr 915.5.4 std::weak_ptr 91第6章 C++2.0多线程原理与实战 93什么是并发 93并发的方式 93为什么使用并发 95线程简介 96创建线程的三种方式 971. 通过函数 972.通过类对象创建线程 993.通过lambda表达式创建线程 101thread线程的使用 101互斥量与临界区 105期物Future 111条件变量 112原子操作 114内存模型 118第7章 C++2.0线程池原理与实战 120线程与线程池的基本原理 1201)、线程 1202)、线程的生命周期 1213)、什么是单线程和多线程 1214)、线程池 1225)、四种常见的线程池 123线程池的架构与流程 123线程池代码实战 125    

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧