C++几种析构

news/2024/6/29 11:49:54 标签: c++, destructor, delete, 编译器, class, microsoft
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

 

 

首先说下我对完全释放的理解。
完全释放是指经过了这系列的操作, 没有内存泄露。

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


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

如果基类和成员变量的FX都不存在,并且A::A()没写, 那么FA则不存在

最后吧这个空间给变量pa

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

只要是class="tags" href="/tags/DESTRUCTOR.html" title=destructor>destructor是virtual的, 这个~FA必然存在, 因为他需要占据虚表项.

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

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

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


好, 接下来最重要的是 
Class A;
A *pa = new A[2];
class="tags" href="/tags/DELETE.html" title=delete>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是否存在!

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

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


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




对照上述不难发现
一: 
class A; 
class B : public A 
//假设类B比类A要大,则: 

A* pA = new B; 
class="tags" href="/tags/DELETE.html" title=delete>delete pA; 
B或者A有虚析构, 一切工作正常,
否则B的析构函数不被调用, B的成员类对象不被析构, 但是
operator class="tags" href="/tags/DELETE.html" title=delete>delete的时候能够pa占据的地址释放, 因为单继承是同一地址


二:
class A; 

void* p = new A; 
class="tags" href="/tags/DELETE.html" title=delete>delete p; 
因为是原生类型, 所以直接operator class="tags" href="/tags/DELETE.html" title=delete>delete掉了, 地址是A的地址,能够正确释放
但是~FA或者~FA2都不会被调用, 可能会A锁包含的指针, 对象, 基类等占据的各种资源不被释放

三:
struct s 

int i; 
int j; 
}; 

LPBYTE pData = new BYTE[100]; 
struct s* ps = (struct s*) pData; 
class="tags" href="/tags/DELETE.html" title=delete>delete ps; 
显然没加[]的是一个单对象析构, 但是~Fs2是不存在的, 所以不被调用,
只是operator class="tags" href="/tags/DELETE.html" title=delete>delete, 地址也对上了.

四: 
class

void Release(){class="tags" href="/tags/DELETE.html" title=delete>delete this;} 
}; 

class B : public A 

int i; 
}; 

B* pb = new B; 
pb->Release(); 
这个Release是因为A生成的, 所以这个class="tags" href="/tags/DELETE.html" title=delete>delete this其实是删除A,
由于A和B的地址相同, 所以空间能释放, 也能正确的调用~FA2, 但是~FB2没机会被调用了
庆幸的是他们都不存在.



关于__stdcall的说明,作为一个微软特有的调用约定限制符, msdn有详细的说明
Microsoft Specific

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype


http://www.niftyadmin.cn/n/562772.html

相关文章

HTML5期末大作业:美食餐厅网站设计——一千一夜美食餐厅(11页) 食品网页设计作业,海鲜网页制作作业, 大众食品学生网页作业, 美食网页作业成品, 食物网页作业模板 ,甜品网页作业定制

HTML5期末大作业:美食餐厅网站设计——一千一夜美食餐厅(11页) 食品网页设计作业,海鲜网页制作作业, 大众食品学生网页作业, 美食网页作业成品, 食物网页作业模板 ,甜品网页作业定制 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器…

Ogre编译错误

错误 C2061: 语法错误: identifier __RPC__out_xcount_part 用VS2010编译Ogre的时候出现这个错误,找了一下午终于问题解决,原来是电脑上装的Directx SDK版本太低了,重新装最新的DX SD&#x…

HTML5期末大作业:餐饮网站设计——简洁的餐饮网(8页) HTML+CSS+JavaScript HTML+CSS大作业: 饮食网页制作作业_食品网页设计...

HTML5期末大作业:餐饮网站设计——简洁的餐饮网(8页) HTMLCSSJavaScript HTMLCSS大作业: 饮食网页制作作业_食品网页设计… 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体…

VS2010 Loadlibrary失败【解决】

系统错误,参数不正确。。。 应该是说加载的DLL格式不正确。 在编译DLL的时候将编译选项嵌入清单选否,或者不启用增量编译 问题解决 总结一下经验,以备后忘。 1.找不到指定模块原因:要加载的DLL依赖于其他的DLL,系…

HTML5期末大作业:甜品奶茶网站设计——大气的甜品奶茶(23页) web前端设计与开发期末作品/期末大作业

HTML5期末大作业:甜品奶茶网站设计——大气的甜品奶茶(23页) web前端设计与开发期末作品/期末大作业 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 …

关于C++ try catch 不能捕获到SEH异常的问题

在项目属性->C->启用C异常 设置为:有,但有SEH异常(EHa)

HTML5期末大作业:美食餐饮网站设计——酥麻辣祸-美食餐饮 HTML+CSS+JavaScript 学生DW网页设计

HTML5期末大作业:美食餐饮网站设计——酥麻辣祸-美食餐饮 HTMLCSSJavaScript 学生DW网页设计 常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 …

CreateDialog Function

CreateDialog Function 发送反馈CreateDialog 宏从一个对话框模板资源创建一个非模态对话框,CreateDialog 宏使用 CreateDialogParam 函数语法 以带有颜色区分的格式查看复制到剪贴板打印HWND CreateDialog(__in HINSTANCE hInstance,__in LPCTSTR lpTemplate,__i…