C++析构函数调用异常问题研究
最近又遇到一个奇葩问题,程序在自己的开发机器和某些机器上运行完好,但是在测试人员的几台机器上运行就直接推出了。开始以为是出现了野指针,因为delete野指针时程序会直接退出。代码翻来覆去过来即便确认没有野指针后问题就陷入了死循环。经过多次调试我发现在我的机器上虽然不崩溃,但是delete对象指针的时候不会走对应的析构函数,这问题就奇怪了。后来终于被我找到了原因。原来在头文件中声明成员变量指针时为了尽量少的包含头文件而使用的前向声明,而在实现文件中又没有包含真正声明该类型的头文件。一般情况下这种使用方式编译器会报错,但是当把指针放在容器中时编译器就不能侦测到错误了。说起来问题比较绕下面用代码写了个例子:
father.h
#ifndef FATHER_H_
#define FATHER_H_ struct FatherCalss
{
public:
virtual double Speak() = ;
virtual ~FatherCalss(); }; struct SonCalss:public FatherCalss
{
public: virtual ~SonCalss(); }; class GrandsonClass:public SonCalss
{
public:
virtual double Speak(); virtual ~GrandsonClass();
}; #endif//FATHER_H_
father.cpp
#include "stdafx.h"
#include "Father.h"
#include <Windows.h> FatherCalss::~FatherCalss()
{
MessageBox(NULL, _T("FatherCalss"), _T("~FatherCalss"), MB_OK);
} SonCalss::~SonCalss()
{
MessageBox(NULL, _T("SonCalss"), _T("~SonCalss"), MB_OK);
} GrandsonClass::~GrandsonClass()
{
MessageBox(NULL, _T("GrandsonClass"), _T("~GrandsonClass"), MB_OK);
} double GrandsonClass::Speak()
{
MessageBox(NULL, _T("Speak"), _T("~GrandsonClass"), MB_OK);
return 0.0;
}
first.h
#ifndef FIRST_H__
#define FIRST_H__
#include <vector> struct FatherCalss; class First
{
public:
void CreateObject();
~First(); std::vector<FatherCalss*> m_VecpFather;
}; #endif // First_h__
first.cpp
#include "First.h"
#include "Father.h" void First::CreateObject()
{
FatherCalss* pFth = new GrandsonClass;
pFth->Speak();
m_VecpFather.push_back(new GrandsonClass);
} First::~First()
{
for(std::vector<FatherCalss*>::iterator it = m_VecpFather.begin(); it != m_VecpFather.end(); ++it)
{
delete *it;
}
}
调用代码:
First* pFirst = new First; pFirst->CreateObject(); for(std::vector<FatherCalss*>::iterator it= pFirst->m_VecpFather.begin(); it != pFirst->m_VecpFather.end(); ++it)
{
delete *it;
}
pFirst->m_VecpFather.clear(); delete pFirst;
如上如果 m_VecpFather 不是容器而是 FatherCalss* 则编译器会报错。
运行程序后会发现对象的析构函数根本就没有被执行,这样的行为存在一定的不确定性,程序如果不报错的换实际上会产生内存泄漏。
C++析构函数调用异常问题研究的更多相关文章
- C++构造函数和析构函数调用虚函数时都不会使用动态联编
先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void ...
- C++单继承的构造函数和析构函数调用的顺序
1.继承构造函数调用顺序以及销毁的过程 先调用父类的构造函数,在调用子类的构造函数,析构函数调用相反.
- c++深/浅拷贝 && 构造函数析构函数调用顺序练习题
1.深/浅拷贝 编译器为我们提供的合成拷贝构造函数以及合成的拷贝赋值运算符都是浅拷贝.浅拷贝只是做简单的复制,如果在类的构造函数中new出了内存,浅拷贝只会简单的复制一份指向该内存的指针,而不会再开辟 ...
- TCP异常关闭研究分析
版权声明:本文由谢代斌原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108 来源:腾云阁 https://www.qclo ...
- 从 C# 崩溃异常 中研究页堆布局
一:背景 1.讲故事 最近遇到一位朋友的程序崩溃,发现崩溃点在富编辑器 msftedit 上,这个不是重点,重点在于发现他已经开启了 页堆 ,看样子是做了最后的挣扎. 0:000> !analy ...
- c++构造函数析构函数调用顺序
#include <iostream> using namespace std; class A { public: A () { cout<<"A 构造 " ...
- C++ 构造函数或析构函数调用虚函数
构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类 ...
- C++类的继承中构造函数和析构函数调用顺序例子
/*当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止.简而言之,对象是由“底层向上”开始构造的.因为,构造函数 ...
- C++中构造函数和析构函数调用的时机
今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 #include <iostream> using name ...
随机推荐
- Atiti qq空间破解(3)------------gui图形化通用cli执行器atiuse
Atiti qq空间破解(3)------------gui图形化通用cli执行器atiuse 结构:::命令行+以及反馈log框1 cli_guiUI/index.htm1 /AtiPlatf_c ...
- WPF中关于自定义控件的滚动条鼠标停留在内容上鼠标滚轮滚动无效的问题
问题起因:在一个用户控件里放置了1个TreeView垂直顺序放置. 当用户控件中的内容超过面板大小时,滚动条会自动出现 ,但是只有当鼠标指示在右边滚动条的那一条位置时,才支持鼠标滚轴滚动. 点在控件内 ...
- Apache多站点实现原理和配置
Apache多站点实现原理 很多人常常看到一台服务器上跑多个站点,不同的域名访问不同的站点,就会有个疑惑:访问的时候并没有在地址栏中加入端口号,多个域名都是解析到这个服务器的IP地址,服务器怎么能够正 ...
- QTP11的下载地址和破解教程
qtp11 下载地址 http://pan.baidu.com/s/1rE3l6 qtp10的破解 下载注册机http://ishare.iask.sina.com.cn/f/20991520.htm ...
- 【译】怎样编写移动优先的CSS
原文:How To Write Mobile-first CSS 作者: 译者:huansky 构建响应式网站是今天前端开发人员必备的技能. 当我们谈论响应式网站时,移动优先这个词立刻就会浮现. 我们 ...
- CCNA网络工程师学习进程(6)vlan相关协议的配置与路由器简单配置介绍
前面已经介绍了大部分与vlan技术相关的交换机的协议的配置,更深层次的还有STP协议和以太网端口聚合技术,接着还会简单介绍一下路由器的基本应用. (1)STP(Spanning-tre ...
- CSS垂直三列居中,中间自适应
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Unity 碰撞检测中碰撞器与触发器的区别
要产生碰撞必须为游戏对象添加刚体(Rigidbody)和碰撞器,刚体可以让物体在物理影响下运动.碰撞体是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞.如果两个刚体相互撞在一起,除非两个对 ...
- 后端码农谈前端(CSS篇)第五课:CSS样式
一.背景: CSS 允许应用纯色作为背景,也允许使用背景图像创建相当复杂的效果. 1.背景色 可以使用 background-color 属性为元素设置背景色.这个属性接受任何合法的颜色值. 例如: ...
- OCP-052 & 053部分答案解析
OCP~052 . GRANT ANY OBJECT PRIVILEGE(授予任何对象权限):允许被授权人将其本身不拥有的对象的对象权限授予他人,但不能授予自己. . ENABLE VALIDATE ...