问题就是SAFE_DELETE((*it)); 这个是在exe中new的,不能在dll中delete。深入:如果一个EXE调用一个DLL时,用new和delete分配和释放内存为什么应该放在同一个背景下的原因。得出的结论是,如果EXE和DLL有一个不是用动态链接CRT库(C runtime library)的方式使用CRT的话(Multi-threaded Debug DLL (/MDd)),或者是EXE和DLL动态链接的CRT库的版本不同时,EXE和DLL将会各自拥有各自的堆空间,所以在DLL中new的东西务必在DLL中delete。
posted on 2011-03-30 17:29 zuhd 阅读(2173) 评论(29) 编辑 收藏 引用 所属分类: c/c++
你去看看vector里面的对象是怎么释放的,就明白了 回复 更多评论
贴下完整的代码 回复 更多评论
@dizhu 问题确实可能出在其他地方。 回复 更多评论
我按你说的做了一遍 没有报错 - -bnr 你咋不把调用的代码发下 回复 更多评论
应该还是也指着啊 回复 更多评论
野指针…… 回复 更多评论
1. 就这段代码本身来说,有一个错误:拷贝构造函数 stReplayData(const stReplayData& src) 里的指针pData没有初始化!2.stReplayData的析构函数本身没有问题。程序报错应该是调用了两次析构函数造成的。比如说,很有可能在使用时会犯这样的错误: stReplayData data(otherdata); vec.push_back(&data);由于data本身会调用析构函数delete pData,而delete vec里面的数据时也会调用data的析构函数,于是挂了。 回复 更多评论
不好意思,第二点我说得不大对,因为楼主在析构函数里判断了 if (pData != NULL), 并且之后会把pData=NULL,所以调用两次析构在单线程环境里不会问题。当然多线程环境下就另说了。但我所陈述的问题依然是存在的,只是这不是因为两次析构造成,而是因为data是栈上的数据,不允许delete,所以挂了。 回复 更多评论
@Mensch88 1. 就这段代码本身来说,有一个错误:拷贝构造函数 stReplayData(const stReplayData& src) 里的指针pData没有初始化! 拷贝构造函数是调用operator =来着 回复 更多评论
@Mensch88vector里面保存的是指针,不会调用delete 的,不会存在你说的两次析构函数调用 回复 更多评论
@dizhu如果楼主stReplayData data(otherdata);vec.push_back(&data);然后还去delete vec里面的数据,那就是楼主代码写的有问题,所以说还是贴下完整的代码,才能知道问题。但就这个stReplayData,还真看不出为什么会挂 回复 更多评论
我更新了帖子 贴了更多的代码 想尝试的朋友 可以自己简单修改下即可 回复 更多评论
问题我找到了,是我以前遇到的老问题 virtual bool PushData(stReplayData* pData); 这个接口设计有问题,dll的接口应该用标准的c++类型,我只知道其然,不知道所以然,了解详情的说下 回复 更多评论
@zuhd重点把delete stReplayData 的代码 和 CReplayManager 贴出来看下 回复 更多评论
@dizhu 看了头文件基本就能猜到代码了吧 中规中矩的容器操作代码而已 另:我在gcc中的头文件大量的使用了自定义的类,貌似没发现过什么问题,怎么用vc上来就碰到这个,是巧合还是必然?肿么办?有没有,有没有? 回复 更多评论
@zuhd我比较关心CReplayManager 的Release 以及 ClearData 的实现。是不是在这里面delete stReplayData 了?? 回复 更多评论
void CReplayManager::ClearData() { VECREPLAY::iterator it = m_vecReplay.begin(); for (; it != m_vecReplay.end(); it++) { SAFE_DELETE((*it)); } m_vecReplay.clear(); } 回复 更多评论
@zuhdvoid CReplayManager::ClearData() { VECREPLAY::iterator it = m_vecReplay.begin(); for (; it != m_vecReplay.end(); it++) { SAFE_DELETE((*it)); } m_vecReplay.clear(); } 问题就是SAFE_DELETE((*it)); 这个是在exe中new的,不能在dll中delete。原因:http://blog.csdn.net/blz_wowar/archive/2008/03/13/2176536.aspx 回复 更多评论
@dizhu 在exe中new,不能在dll中delete的? exe和dll用的是同一个堆栈空间的, 回复 更多评论
zuhd@zuhd--拷贝构造函数是调用operator =来着拷贝构造函数是调用了operator=,但是operator=里面会判断pData是否为NULL: if (pData != NULL) { delete[] pData; pData = NULL; } 必须注意的是,这时pData还没有被初始化。这样就会执行 delete[] pData;从而出错。 回复 更多评论
@dizhu--然后还去delete vec里面的数据,那就是楼主代码写的有问题,所以说还是贴下完整的代码,才能知道问题。但就这个stReplayData,还真看不出为什么会挂因为楼主说了vec里面是一些new出来的指针,而之后程序释放资源时报错,于是我估计楼主所说的程序释放资源就是指将vec里面的指针delete。楼主后来的代码也证实了我的猜测。 回复 更多评论
楼主的问题算是CRT的bug么?Linux下测试,无论是静态还是动态链接都没发现这种问题。 回复 更多评论
建议还是用 vector<char> 或 string 代替 char* stReplayData 设计得有点问题, 一般都是 在拷贝构造函数中进行分配新内存处理, 然后在赋值函数中调用拷贝构造函数,构造一个临时类对像,与原类对象进行交换。 你的实现刚好相反,拷贝构造函数调用 赋值函数,但 赋值函数中用到的 nlen 和 pdata两个值都未初始化,UB行为。 实际上,这两个判断都是可以去掉的,new char[0] 是有意义的,没必要对 nlen进行判断 delete[] p 当p是空指针时,没有任何效果,因此没必要对pdata进行判断 拷贝构造函数中 对指针的判断 也是多余的。 另外,要先分配新内存,再释放旧内存,保证 异常安全。 回复 更多评论
@flyinghearts 那个拷贝构造函数确实有点问题,以前拷贝构造函数调用=写顺手了,没发现有内存操作的这么写有这个陷阱,改了一下: stReplayData(const stReplayData& src) { if (this == &src) { return; } nDelay = src.nDelay; nLen = src.nLen; pData = new char[nLen]; if (pData != NULL) { memcpy(pData, src.pData, nLen); } } stReplayData& operator = (const stReplayData& src) { if (this == &src) { return *this; } nDelay = src.nDelay; nLen = src.nLen; if (pData != NULL) { delete[] pData; pData = NULL; } pData = new char[nLen]; if (pData != NULL) { memcpy(pData, src.pData, nLen); } return *this; } 至于你说的: 另外,要先分配新内存,再释放旧内存,保证 异常安全。 好像我一直都是先delete 再new ,可能一直懒得用个临时的指针来保存pData吧,不过你这么说的道理是?? 回复 更多评论
如果楼主使用 /mt 编译,dll启动时使用自己的堆, 在主程序中new 出来的对象,再通过指针传给dll,然后在dll中释放,会产生错误,主程序和dll使用不同的堆。 回复 更多评论
把struct改为class,然后把数据private,测试一次看看。排除客户代码应用上的错误。当然了,也有可能在调用的时候,被其他地方的错误牵连导致这个struct的数据被损坏。如果牵扯到DLL的话,那有可能是exe和dll两者之间的版本不一致所导致,DLL的导出地址是用的一个,却不想exe用了另外一个,所以发生错误,这是有可能发生的。用VS的编译器,特别是2003,你需要依照以下步骤重编译:清理全部(包括dll和exe)->重编。 回复 更多评论
http://blog.csdn.net/ssli/archive/2009/06/16/4272484.aspx 回复 更多评论
涉及到跨模块内存使用的问题,应该遵守谁使用,谁释放 回复 更多评论
Powered by: C++博客 Copyright © zuhd