晓说智能指针shared_ptr为何可以实现跨模块分配和释放内存
最近做项目, 有个地方是外包人员写的, 其中有个函数,大致这样
void getInfo(std::shared_ptr<Info>& outInfo); 这个函数是一个dll(链接静态vc库, 使用/MT链接选项)。
我在exe(也是/MT选项)中使用这个函数, 一开始看了,感觉危险,为啥呢?因为我是这样调用的
f()
{
std::shared_ptr<Info> tmpInfo;
getInfo(tmpInfo);
}
所以,内存是在dll里面分配的,但是 内存在f退出时,析构 tmpInfo, 肯定会有释放的动作,这岂不是 dll分配 , exe释放吗?而且还是静态链接, 必然会 堆冲突啊, 然而无论我怎么测试 , 就是好的出奇, 没有任何挂掉的迹象。 我想了好几天, 也跟了好几次std::shared_ptr的代码, 明明最后看到有 delete p这样的类似语句, 那么delete不是释放了不该管的内存吗?
今天又跟踪, 突然发现一个诡异的问题,发现在f退出前, tmpInfo析构时竟然 代码最后进入到了dll里面进行内存释放的调用,大致就是调用了一个函数 _destroy()的。 我跟了几次, 中间停下来想了各种可能的原因, 后来看到了reset时的一个 调用
shared_ptr(px这是那个分配的指针).swap(*this), 就是相当于 shared_ptr(px).swap(tmpInfo), 于是我就观察 ,跟踪, 发现在shared_ptr(px)临时对象析构时, 竟然进入了exe模块, 明明就是dll中reset内部的临时变量, 咋就跑到exe了呢? 后来发现 跳转时, 有个 call eax的地方, eax经过了几次mov的计算, 所以猜测应该是虚函数指针寻址进行调用的过程。
后来想了想, 觉得可能就是在swap时 , 临时的shared_ptr从(*this)中交换到了this对象初始化时所在模块的 delete地址, 所以才正确分配this相关的内存。
结合前几次看源代码的过程, 里面有几个对象定义了虚函数, 尤其是_destroy是虚函数, 而且使用了一个父类指针作为记忆的东西。 果然, 继续去看源码, shared_ptr有个 _Ref_cout_base*的成员变量,就是它记忆了相关分配时的信息。 他有个纯虚函数—_destroy,在 在 调用 reset时, 回调用 reset(px, new _Ref_count(px)), 这个 _Ref_count就是_Ref_cout_base的具体实现的子类,
这个子类又实现了接口_destroy(), 基本就是delete px的动作。 所以, 一切明了啦。 在reset时, 会同时调用一下类似的动作:
m_pRefCount = new _Ref_count(px); 这样m_pRefCount就跟调用shared_ptr的reset 时所在模块一致了, 所以, shared_ptr使用 临时对象和this对象的swap完成 reset函数的功能, 就可以保证, this对象的m_pRefCount对象所在模块就是reset调用时所在模块(我这里是dll中), 所以,当f 函数退出时, 会调用 m_pRefCount的_destroy函数, 而这个函数会通过虚函数表中记忆的m_pRefCount对象被初始化时所在模块中定义的该类的_destroy函数(虽然exe也有这个类的所有函数定义), 找到正确的_destroy地址, 而这个_destroy由于跟getInfo函数都是在dll定义的一个具体实现, 所以, 这个_destroy中所有的函数的直接调用(仅限于是直接调用(非虚函数的,有固定地址的),如果他也调用一个虚函数, 说不定通过虚函数表的寻址,又跑了其他模块去了,正如他自己就是这样跨模块的), 就是调用了dll里面的函数(包括delete), 所以, tmpInfo析构时, 调用tmpInfo.m_pRefCount的_destroy函数(虚的),会根据虚表指针走到dll函数里面真正的_destroy地址, 这样, 他所释放的也就跟他所包含的对象都在一个模块。这个关键还是 虚函数 的作用啦。
想一想, 如果m_pRefCount不是虚函数, 那么, 对象中就不会包含 他的成员函数地址, 就不会包含m_pRefCount地址(虚函数的地址间接存放在对象开头), 那么reset就交换不到外部模块函数地址, 当调用_destroy时, 就是调用了所在模块的_destroy, 就会调用所在模块的delete, 这样释放就会有问题。 所以, 正式因为虚函数的作用, 我们可以在对象本身中存放函数地址(固定的cpu寻函数地址指令就可以找到地址), 就可以记忆delete的地址(虽然delete很奇特的编译器实现的东西,语言上不可操控), 这样才可以保证对象的一致释放~~~~ 好啦, 回去睡觉啦, 还在公司呢, 刚吃个水饺, 欧耶~~~~~~
晓说智能指针shared_ptr为何可以实现跨模块分配和释放内存的更多相关文章
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- c/c++ 智能指针 shared_ptr 和 new结合使用
智能指针 shared_ptr 和 new结合使用 用make_shared函数初始化shared_ptr是最推荐的,但有的时候还是需要用new关键字来初始化shared_ptr. 一,先来个表格,唠 ...
- c/c++ 智能指针 shared_ptr 使用
智能指针 shared_ptr 使用 上一篇智能指针是啥玩意,介绍了什么是智能指针. 这一篇简单说说如何使用智能指针. 一,智能指针分3类:今天只唠唠shared_ptr shared_ptr uni ...
- C++智能指针shared_ptr
shared_ptr 这里有一个你在标准库中找不到的—引用数智能指针.大部分人都应当有过使用智能指针的经历,并且已经有很多关于引用数的文章.最重要的一个细节是引用数是如何被执行的—插入,意思是说你将引 ...
- 标准库中的智能指针shared_ptr
智能指针的出现是为了能够更加方便的解决动态内存的管理问题.注:曾经记得有本书上说可以通过vector来实现动态分配的内存的自动管理,但是经过试验,在gcc4.8.5下是不行的.这个是容易理解的,vec ...
- C++ 智能指针 shared_ptr 分析
引文: C++对指针的管理提供了两种解决问题的思路: 1.不允许多个对象管理一个指针 2.允许多个对象管理一个指针,但仅当管理这个指针的最后一个对象析构时才调用delete ps:这两种思路的共同点就 ...
- STL源码剖析-智能指针shared_ptr源码
目录一. 引言二. 代码实现 2.1 模拟实现shared_ptr2.2 测试用例三. 潜在问题分析 你可能还需要了解模拟实现C++标准库中的auto_ptr一. 引言与auto_ptr大同小异,sh ...
- 智能指针 shared_ptr 解析
近期正在进行<Effective C++>的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦.写篇blog整理一下. LinJM @HQU s ...
- 智能指针shared_ptr
// 智能指针会自动释放所指向的对象. // shared_ptr的应用场景是:程序需要在多个对象间共享数据 /* 先从应用场景入手吧,说矿工A发现了一个金矿. * 然后矿工A喊来了矿工B,一起开采, ...
随机推荐
- ExtJs MVC应用架构示例
项目目录结构 (源码)2. app.js Ext.Loader.setConfig({ enabled : true, paths : { 'Ext' : 'extjs', 'App' : 'app' ...
- java指纹识别+谷歌图片识别技术
http://www.icodeguru.com/3/2451.html http://valseonline.org/thread-124-1-1.html
- 玩玩SPARK
没有SCALA的东东,玩不起哈. ./spark-shell 从文件生成一个DRIVER? val logFile = sc.textFile("hdfs://192.168.14.51:9 ...
- latch:library cache
一:硬解析造成的shared pool latch 争用: 每一个sql被执行之前,先要到library cache中根据hash_value查找parent cursor,这就需要先获得librar ...
- Delphi对ini文件的操作
一.INI文件的结构:; 注释[小节名]关键字=值 INI文件允许有多个小节,每个小节又允许有多个关键字, “=”后面是该关键字的值. 值的类型有三种:字符串.整型数值和布尔值.其中字符串存贮在INI ...
- Tuna项目总结
从8.19—9.13日一共四周的时间,我在Tuna项目组进行的我的第一次正式工作,以及学习.在此,我对这个阶段的工作及学习进行一个总结,主要分为对流程的理解和对自动化测试的应用两个方面. 在总结着两点 ...
- Java的内存管理与内存泄露
作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端.服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存 ...
- 下载cppunit
cppunit的官方地址:http://sourceforge.net/projects/cppunit 方式一:下载打包好的版本 下载地址:http://sourceforge.net/projec ...
- [置顶] 【Git入门之九】解决冲突
原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/12309531 1.多人协作冲突 如果多人同时修改了同一个文件,那会出现什么样 ...
- springmvc对jsonp的支持
在与前端开发人员合作过程中,经常遇到跨域名访问的问题,通常我们是通过jsonp调用方式来解决.jsop百科:http://baike.baidu.com/link?url=JKlwoETqx2uuKe ...