最近又遇到一个奇葩问题,程序在自己的开发机器和某些机器上运行完好,但是在测试人员的几台机器上运行就直接推出了。开始以为是出现了野指针,因为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++析构函数调用异常问题研究的更多相关文章

  1. C++构造函数和析构函数调用虚函数时都不会使用动态联编

    先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void ...

  2. C++单继承的构造函数和析构函数调用的顺序

    1.继承构造函数调用顺序以及销毁的过程 先调用父类的构造函数,在调用子类的构造函数,析构函数调用相反.

  3. c++深/浅拷贝 && 构造函数析构函数调用顺序练习题

    1.深/浅拷贝 编译器为我们提供的合成拷贝构造函数以及合成的拷贝赋值运算符都是浅拷贝.浅拷贝只是做简单的复制,如果在类的构造函数中new出了内存,浅拷贝只会简单的复制一份指向该内存的指针,而不会再开辟 ...

  4. TCP异常关闭研究分析

    版权声明:本文由谢代斌原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108 来源:腾云阁 https://www.qclo ...

  5. 从 C# 崩溃异常 中研究页堆布局

    一:背景 1.讲故事 最近遇到一位朋友的程序崩溃,发现崩溃点在富编辑器 msftedit 上,这个不是重点,重点在于发现他已经开启了 页堆 ,看样子是做了最后的挣扎. 0:000> !analy ...

  6. c++构造函数析构函数调用顺序

    #include <iostream> using namespace std; class A { public: A () { cout<<"A 构造 " ...

  7. C++ 构造函数或析构函数调用虚函数

    构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类 ...

  8. C++类的继承中构造函数和析构函数调用顺序例子

    /*当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止.简而言之,对象是由“底层向上”开始构造的.因为,构造函数 ...

  9. C++中构造函数和析构函数调用的时机

    今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 #include <iostream> using name ...

随机推荐

  1. easyui combotree下拉框多选赋值

    发现jquery.easyui.min.js 1.3.4版本的用setValues给多选下拉框赋值不成功,只能用1.3.1版本的 Html代码: <input id="ProductL ...

  2. SpringSide 部署showcase项目出现 JAX-RS (REST Web Services) 2.0 can not be installed错误!

    maven+springmvc错误 JAX-RS (REST Web Services) 2.0 can not be installed 项目problem提示错误 JAX-RS (REST Web ...

  3. 彻底理解跨域解决方案JSONP

    什么是同源策略? 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略. 所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab页 ...

  4. 理解模板引擎Razor 的原理

    Razor是ASP.NET MVC 3中新加入的技术,以作为ASPX引擎的一个新的替代项.简洁的语法与.NET Framework 结合,广泛应用于ASP.NET MVC 项目.Razor Pad是一 ...

  5. HTML内联元素

    前面的话 用于标记段落里的文本和其他内容组的元素种类很多,本文将这些文本级元素进行简单分类,便于整理和记忆 通用容器 <span>元素是短语内容的通用行内容器,并没有任何特殊语义.可以使用 ...

  6. Android切换动画之ViewPager

    有过开发经验的程序员都知道这个效果,就是当我们第一次安装一个软件时有一个使用说明的图片切换效果,他是如何实现的呢?今天我们就一起学习一下吧,难度系数1.0,就是只要你仔细分析,都可以学会.废话不多说, ...

  7. vs xamarin android 监听返回键退出程序

    public override bool OnKeyDown([GeneratedEnum]Keycode keyCode, KeyEvent e) { if (keyCode == Keycode. ...

  8. Windows常用技巧集锦

    1. Word中如何消除回车符 文件—选项—显示—勾掉段落标记 2. Windows不重启就使环境变量修改生效 以修改环境变量“PATH”为例,修改完成后,进入DOS命令提示符,输入:set PATH ...

  9. 使用ZeroClipboard解决跨浏览器复制到剪贴板的问题

    Zero Clipboard的实现原理Zero Clipboard 利用透明的Flash让其漂浮在复制按钮之上,这样其实点击的不是按钮而是 Flash ,这样将需要的内容传入Flash,再通过Flas ...

  10. 《Selenium2自动化测试实战--基于Python语言》 --即将面市

    发展历程: <selenium_webdriver(python)第一版>   将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...