#pragma warning (disable : 4786)
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
class A
{
public:
~A() { }
void pOut()
{
doOut();
}
virtual void doOut() = 0;
};
class BA: public A
{
public:
~BA() { }
virtual void doOut()
{
cout << m_i << endl;
}
int m_i;
};
class CA: public A
{
public:
string m_str;
~CA() {}
virtual void doOut()
{
cout << m_str << endl;
}
};
class DA : public A
{
public:
~DA();
void clear();
vector<A *> m_vec;
virtual void doOut();
};
class EA : public A
{
public:
virtual void doOut();
void clear();
~EA()
{
clear();
}
map<string, A*> m_map;
};
void DA::doOut()
{
vector<A *>::iterator it;
for (it = m_vec.begin(); it != m_vec.end(); it++)
{
(*it)->doOut();
}
}
void EA::doOut()
{
map<string, A*> ::iterator it;
for (it = m_map.begin(); it != m_map.end(); it++)
{
cout << (*it).first << " ===> " << endl;
(*it).second->doOut();
}
}
void EA ::clear()
{
map<string, A*> ::iterator it;
for (it = m_map.begin(); it != m_map.end(); it++)
{
cout << (*it).first << " ===> " << endl;
(*it).second->doOut();
delete (*it).second;
}
}
DA::~DA()
{
clear();
}
void DA::clear()
{
vector<A *> ::iterator it = m_vec.begin();
for (it; it != m_vec.end(); it++)
{
delete (*it);
}
m_vec.clear();
}
/*
void foo(A *pa)
{
BA *pca1 = static_cast<BA *> ( pa );
cout << "in function foo(), pca1->doOut() " << endl;
pca1->doOut();
BA *pca2 = dynamic_cast<BA *> ( pa );
cout << "in function foo(), pca2->doOut() " << endl;
pca2->doOut();
}
*/
int main()
{
BA *pBa = new BA;
pBa->m_i = 100;
CA *pCa = new CA;
pCa->m_str = "myprogram";
DA da;
da.m_vec.push_back(pBa);
da.m_vec.push_back(pCa);
// foo(pa1);
//请问一下,我要在这里输出da.m_vec的所有内容,应该如何实现呢?
//da.doOut();
DA *pDa2 = new DA;
pDa2->m_vec.push_back(pBa);
pDa2->m_vec.push_back(pCa);
pDa2->doOut();
delete pDa2;
return 0;
}
上面这段程序执行后会出错,
因为delete pDa2时,已经把pBa, pCa给删除了,所以,而在return 0;执行之前,会调用da的析构函数,而在此之前,调用pDa2的析构函数的时候,已经把pBa,pCa给释放掉了,所以,调用da的析构函数时,再次释放pBa, pCa所指的内存空间会出错。
见下帖:
对一个指针进行两次delete操作,会出现什么结果?
// 有如下程序:
class Test
{
public:
Test() : m_id( s_count++ )
{
cout << "created: " << m_id << endl;
}
~Test()
{
cout << "destroyed: " << m_id << endl;
}
private:
static in s_count;
int m_id;
};
int Test::s_count = 0;
void main()
{
Test *pTest = new Test[3];
delete pTest;
delete pTest;
}
/*
程序输出结果:
created: 0
created: 1
created: 2
destroyed: 0
destroyed: 0
*/
-----------------------------------------------------------
1.为什么可以对指针p进行两次delete操作?为什么这里运行好象并没有出现问题,并且两次操作有同样的输出结果?
2.当我把main()函数改写为
void main()
{
Test *pTest = new Test[3];
delete [] pTest;
}
后,程序输出的结果为
created: 0
created: 1
created: 2
destroyed: 2
destroyed: 1
destroyed: 0
那为什么原先的那个程序的最后两行输出结果为
destroyed: 0
destroyed: 0
却不是
destroyed: 2
destroyed: 2
?
注意:这个程序本身就有问题,运行会造成内存泄漏,所以这里我想讨论的不是程序的安全性问题,而是关注于其输出结果,为什么会有这样的输出结果呢?
另外,我使用的是VC6 + Windows XP。
问题点数:50、回复次数:21Top
1 楼gorge_an(木头)回复于 2004-07-06 16:07:40 得分 0
学好C语言Top
2 楼yjh1982(血精灵)回复于 2004-07-06 16:08:49 得分 0
什么结果都有:)Top
3 楼dingfuhao(丁丁)回复于 2004-07-06 16:37:15 得分 10
这个问题是和编译器有一定的关系
在VC中,Debug模式下如果你释放内存,编译器会将释放内存的内容填充成0xEEFE
当你再次释放的时候会有断言错误.而在Release模式下,释放内存后,内存的内容并
不改变,所以你两次调用可以得到相同的结果
为什么是destroyed: 0, 是因为你释放pTest = pTest[0];
Top
4 楼xjp6688(大平/要做必须最好)回复于 2004-07-06 16:41:04 得分 0
什么是DEBUG模式,什么是RELEASE模式?Top
5 楼peter9606( 荷尔蒙一失效 人就清醒了)回复于 2004-07-06 16:49:09 得分 0
Test *pTest = new Test[3];
delete pTest;
delete pTest;
运行没有错误么?
Top
6 楼jwwu(开始懂了)回复于 2004-07-06 16:50:33 得分 10
和编译器有很大的关系
有时候
char *p = char[100];
sprintf(p, "hello the world/n");
cout << p << endl;
delete []p;
cout << p << endl;
还能出结果
最好的方式是
delete []p;之后p = (char *)0;
Top
7 楼peter9606( 荷尔蒙一失效 人就清醒了)回复于 2004-07-06 17:08:49 得分 0
同意 jwwu(永不放弃)Top
8 楼BlueprintIrene(我只能用程序来麻痹自己)回复于 2004-07-06 17:12:10 得分 0
To dingfuhao(丁丁):
是不是可以这样认为:
delete pTest; // pTest = &pTest[0],你好象有笔误
释放的是数组第一个元素,
而
delete [] pTest;
却是从数组尾部开始释放内存的?
Top
9 楼dingfuhao(丁丁)回复于 2004-07-06 17:23:32 得分 10
delete pTest调用的是operator delete函数, 只调用了pTest->~Test()函数, 故只
显示destory 0
而delete[] pTest调用的是operator delete[]函数, operator delete[] 实现对应于operator new []函数, 基于先创建的对象后销毁的原则, 创建的顺序是0->1->2,
而销毁的顺序时2->1->0Top
10 楼peter9606( 荷尔蒙一失效 人就清醒了)回复于 2004-07-06 17:26:11 得分 0
To 楼主:
如果你这样定义 : int* p = new int[10] ;
那么你就这样删除: delete []p ;
千万不要问为什么不可一 delete p ; 因为这样是错误的。Top
11 楼BlueprintIrene(我只能用程序来麻痹自己)回复于 2004-07-06 17:31:33 得分 0
To peter9606:
首先,谢谢你的回复
但我在这里,并不是想讨论程序的设计错误之处,而是关注于其输出结果。
关于这一点,我已经在提问的注意中声明过了
呵呵,可能我有点钻牛角尖了吧Top
12 楼BlueprintIrene(我只能用程序来麻痹自己)回复于 2004-07-06 17:32:55 得分 0
谢谢dingfuhao(丁丁)!Top
13 楼ricky460(阿酷)回复于 2004-07-06 17:36:09 得分 0
实际上 , 你的编译模式设置好的话 , 是不应该出现delete 两次指针还能没有错的 . . .
另外 , delete pTest , 这句话的意思是告诉系统 , 删除一个指针 . . . , 于是系统从pTest位置处开始寻找 , 此时pTest指向的是pTest[0],也就是说他释放的是数组第一个元素 .
而 delete [] pTest , 告诉系统的是要删除一个数组 . . .Top
14 楼darkstar21cn(≮天残≯无畏)(死亡进行时)回复于 2004-07-06 18:28:30 得分 10
有些编译器可能能够提示这种“警告”,实行其间是不会有异常的,因为delete在设计的时候没有抛出异常。
主要原因是指针数组,例如:
delete[] p;如果delete抛出异常那么后面的指针将得不到销毁,这就造成了更为严重的内存泄漏Top
15 楼darkstar21cn(≮天残≯无畏)(死亡进行时)回复于 2004-07-06 18:33:11 得分 0
那为什么原先的那个程序的最后两行输出结果为
destroyed: 0
destroyed: 0
却不是
destroyed: 2
destroyed: 2
因为*ptest 指向的是第一个实例就是ptest[0];ptest[0].m_id == 0,OK?Top
16 楼fangrk(加把油,伙计!)回复于 2004-07-06 19:09:22 得分 0
未定义Top
17 楼peter9606( 荷尔蒙一失效 人就清醒了)回复于 2004-07-06 19:14:57 得分 0
嗯。。。
未定义
最恰当的解释了
Top
18 楼kahn(麟)回复于 2004-07-06 19:37:32 得分 10
听说如果不巧释放那个指针先前指向的那个区域在第一次释放后被系统信息覆盖了,那你在第二次释放后会造成系统崩溃Top
19 楼dayn9(无知者无罪)回复于 2004-07-06 21:51:38 得分 0
同意 fangrk(加把油,伙计!),重复释放,是最基本的未定义行为。每人能对其结果做出保证。
同意 kahn(麟),可能的崩溃不是最严重的后果,最严重的是可能导致缓存溢出,恭喜你,你有望被黑了。Top
20 楼eagle758(天偌)回复于 2004-07-07 10:27:27 得分 0
同意!!!!!darkstar21cn(暗星)Top
21 楼rorot(rorot)回复于 2004-07-07 13:07:04 得分 0
使用auto_ptr试试.....