MyException - 我的异常网
当前位置:我的异常网» VC/MFC » 这几种内存释放方式,正确与否,能不能完全释放内存

这几种内存释放方式,正确与否,能不能完全释放内存?该怎么解决

www.MyException.Cn  网友分享于:2013-03-02  浏览:200次
这几种内存释放方式,正确与否,能不能完全释放内存?
一:
class A;
class B : public A
//假设类B比类A要大,则:

A* pA = new B;
delete pA;


二:
class A;

void* p = new A;
delete p;


三:
struct s
{
int i;
int j;
};

LPBYTE pData = new BYTE[100];
struct s* ps = (struct s*) pData;
delete ps;


四:
class A
{
void Release(){delete this;}
};

class B : public A
{
int i;
};

B* pb = new B;
pb->Release();



最近我进了一家人数达到六七百人的大公司,我看了一下他们的代码,
上面是我看到的3种内存释放方式,我对程序的正确性表示怀疑!

还有,他们居然用__stdcall来修改可变参数的函数!可是奇怪的是,编译没有问题,运行也没有问题,可能对这个问题,我自己也不懂!
或者,这个函数根本没有执行到。

------解决方案--------------------
这几种方式都会释放内存,delete只要指针的值对就会释放内存。区别在于:
一、如果不是虚析构函数,delete时不会执行~B()。
二、不是执行析构函数。
三、没问题,但要注意,struct与class基本是相同的,delete时也会自动执行析构函数。
四、同一。

使用__stdcall定义可变参数的函数时,__stdcall会自动忽略。
------解决方案--------------------
首先说下我对完全释放的理解。
完全释放是指经过了这系列的操作, 没有内存泄露。

三,四能够完全释放内存, 一,二由于条件不足, 不能确定。
但是四个使用的方式都是错误的, 这四种情况都不会导致运行错误, 可以算是一种巧合。


一点背景知识:
//////////////////////////////////////////////////
Class A;
A *pa = new A;
首先调用operator new(size_t) 来分配A所占据的内存空间, 然后在这个空间上调用一个函数,记做函数FA(注意不是A::A()):
{
构造基类 // 如果有 
构造成员对象变量 // 如果有
调用自己的构造函数 // 如果有 A::A()
}
这是一个递归的过程, 既基类和成员变量的构造也有自己的FX函数。

如果基类和成员变量的FX都不存在,并且A::A()没写, 那么FA则不存在
color]
最后吧这个空间给变量pa

Class A;
Class B : public A;
A *pa = new B;
delete pa;
这里分两种情况, 如果有virtual destructor和没有virtual destructor的情况
A或者A的任何层次继承的基类具有virtual destructor, 那么A则具有virtual destructor,否则则不具有。
有virtual destructor:
直接调用这个虚函数记做~FA (注意不是A::~A()), 因为虚函数的多态特性, 保证了
“对一个具有虚析构函数的基类指针调用delete, 能完全释放内存, 即便这个指针可能是派生类所产生的”
这是设计一个基类必须需要做的一件事, 比如你需要让别人继承你的话, 最起码要写一个空的虚析构函数。
c++的这个特性的实现一般采用这个过程。 这个在B的虚表中的~FA一般是这样的.
~FA thiscall (A *this, int flag)
{
// 注意这里传递过来的this是A级别的, 因为这个函数的产生是因为A导致的!!
调用B的析构函数B::~B() // 如果存在的话, 这里需要有一个修正this的过程, 即编译器根据A和B的层次
// 关系来修正, 对于单重派生来说, 是一样的。
析构B中的其他成员类对象
析构基类
if (flag & 1)
operator delete (void*) // 释放内存
}
注: 这也是个递归的过程, 其中 "析构B中的其他成员类对象" 和 "析构基类" 分别有自己的~FX函数
关于这个flag是用来区别delete pa 和 pa->~A() 的.
[color=#FF0000]
只要是destructor是virtual的, 这个~FA必然存在, 因为他需要占据虚表项. 

没有virtual的destructor
编译器会生成一个函数记做~FA2, 看起来像这个样子
~FA2 thiscall (A *this)
{
调用A的析构函数A::~A();
析构A的其他成员类对象
析构A的基类
 }
这也是个递归的过程, 同样, 还存在一个函数, 记做~FB2, 看起来是这个样子
~FB2 thiscall (B *this)
{
调用B的析构函数B::~B();
析构B的其他成员类对象
析构B的基类 // 即函数 ~FA2
}

执行delete pa的时候, 编译器
调用~FA2(), 然后在吧A层次的空间去调用operator delete(void *)
~FA2的不存在的条件是,A::~A()没有写并且他所有的基类和成员类对象的~FX都不存在。
A的其他成员类对象的则根据是否是virtual destructor来按照这两种法则析构.
如果是法则1则flag传递的是0.

这里有2个问题:
1: 没有经过FB2, 所以B的析构函数B::~B()和B的其他成员类对象没可能释放。
2: A层次空间的地址肯能不是B层次空间的地址, 强制operator delete可能会出错, 
虽然大多数情况下是一样的


好, 接下来最重要的是 
Class A;
A *pa = new A[2];
delete []pa;
第一次分配了多少内存?
可能是sizeof(A)*2 也可能是sizeof(A)*2 + sizeof(size_t)
第一种情况吧operator []new(size_t)的地址给pa
第二种情况吧operator []new(size_t) + sizeof(size_t)的地址给pa

这完全看这个~FA或者~FA2是否存在!

为什么这么说, 看看delete[]pa吧,
[]告诉编译器这是一个数组对象的析构, 我需要吧析构的过程应用到
所有的对象上, 所以我必须知道对象的个数, 然后吧从这个地址开始的每个
对象都去析构一把, 这个个数则记录在pa这个地址-sizeof(size_t)的地方!

但是, 如果析构是无动作的, 则没有记录这个size的必要


一点小的细节就是A如果是virtual destructor则循环调用那个虚函数
否则编译器可能生成一个 vector_~FA2(A *this, int flag)来释放
if (flag & 2) 则是一个vector析构,需要循环, 否则是就是~FA2(A *this, int flag)

文章评论

要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
 程序员的样子
程序员的样子
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
10个调试和排错的小建议
10个调试和排错的小建议
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
总结2014中国互联网十大段子
总结2014中国互联网十大段子
程序员必看的十大电影
程序员必看的十大电影
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
为什么程序员都是夜猫子
为什么程序员都是夜猫子
Java程序员必看电影
Java程序员必看电影
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
一个程序员的时间管理
一个程序员的时间管理
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
那些争议最大的编程观点
那些争议最大的编程观点
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员和编码员之间的区别
程序员和编码员之间的区别
我是如何打败拖延症的
我是如何打败拖延症的
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
程序员都该阅读的书
程序员都该阅读的书
代码女神横空出世
代码女神横空出世
我的丈夫是个程序员
我的丈夫是个程序员
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
每天工作4小时的程序员
每天工作4小时的程序员
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
程序员应该关注的一些事儿
程序员应该关注的一些事儿
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
漫画:程序员的工作
漫画:程序员的工作
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
编程语言是女人
编程语言是女人
程序员的鄙视链
程序员的鄙视链
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
鲜为人知的编程真相
鲜为人知的编程真相
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有