最近又遇到一个奇葩问题,程序在自己的开发机器和某些机器上运行完好,但是在测试人员的几台机器上运行就直接推出了。开始以为是出现了野指针,因为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. SQL PASS将于8月24日在北京中医药大学举办线下活动

    活动主题:复制架构的实现和调优以及SQL Server BI在传统行业的应用 地点:北三环东路11号 北京中医药大学 白色的1号楼教学楼后楼5层511房间 时间:2013年8月24日 9:00-12: ...

  2. Implementation Model Editor of AVEVA in OpenSceneGraph

    Implementation Model Editor of AVEVA in OpenSceneGraph eryar@163.com 摘要Abstract:本文主要对工厂和海工设计软件AVEVA的 ...

  3. Topology Shapes of OpenCascade BRep

    Topology Shapes of OpenCascade BRep eryar@163.com 摘要Abstract:通过对OpenCascade中的BRep数据的读写,理解边界表示法的概念及实现 ...

  4. 数据结构:JAVA_二叉数查找树基本实现(中)

    数据结构:二叉数查找树基本实现(JAVA语言版) 1.写在前面 二叉查找树得以广泛应用的一个重要原因是它能保持键的有序性,因此我们可以把它作为实现有序符号表API中的众多方法的基础. 也就是说我们构建 ...

  5. [转载]TFS源代码管理

    以下主要描述了: TFS源代码控制系统的基本场景 如何把一个项目添加到源代码管理中 如何与服务器同步 如何做Check-In 如何做分支与合并 什么是上架与下架 我们知道工作项是项目管理的基本元素,但 ...

  6. 优秀工具推荐:超实用的 CSS 库,样板和框架

    当启动一个新的项目,使用 CSS 框架或样板,可以帮助您节省大量的时间.在这篇文章中,我编译整理了我最喜欢的 CSS 样板,框架和库,帮助你在建立网站或应用程序时更加高效. 您可能感兴趣的相关文章 精 ...

  7. 【转】 制作Android Demo GIF:程序演示效果GIF图录制

    在平时写博客或者分享自己写的程序效果的时候经常需要做成GIF图,以下就是介绍几种常用的GIF录制方法: 一.录制工具 1.(生成动画的工具:Ulead GIF Animator),可以讲单独的图片生成 ...

  8. Windows Azure HandBook (9) Azure性能测试(2)

    <Windows Azure Platform 系列文章目录> 在上一节中,笔者介绍了我们在Azure性能测试之前,首先需要提交<渗透性测试表> Windows Azure H ...

  9. CentOS上安装SQL Server vNext CTP1

    今天微软正式发布上SQL Server 2016 SP1,根据以往的SP1定律,可以在生产环境上使用了.打了SP1的标准版将具有企业版几乎所有的的功能.只有RAM 超过128GB或者超过24核心或者超 ...

  10. 计算机中数据实体和数据表示形式(以C#为例)

    摘自网络的一段话: “在程序代码中,可以用多种方式表示数据,十进制.十六进制.八进制都是常用的表示方式,但计算机内部永远就只使用二进制,与你写程序时用什么无关.你说要定义数组int a[10],其中涉 ...