再问关于DLL中的new和delete问题

MulinB 2007-08-10 12:15:30
问题前导:之前跟大家讨论过关于DLL和EXE中堆内存的问题。问题就是,如果一个EXE调用一个DLL时,用new和delete分配和释放内存为什么应该放在同一个背景下的原因。得出的结论是,如果EXE和DLL有一个不是用动态链接CRT库(C runtime library)的方式使用CRT的话,或者是EXE和DLL动态链接的CRT库的版本不同时,EXE和DLL将会各自拥有各自的堆空间,所以在DLL中new的东西务必在DLL中delete。
(对以前的讨论有问题的朋友可以参考我以前发的提问贴,搜 "DLL 内存")。

//////////////////////////////////////////////////////////////////////////

新问题描述:(环境:VC2005)

某workspace下有子工程A、B、C三个,其中,A是静态库(*.lib),B是动态链接库(*.dll), C是应用程序(*.exe)。
他们的关系是,B(DLL)包含了A(LIB),C(EXE)包含了A(LIB),同时C(EXE)使用了B(DLL)。

若其中A(LIB)中有代码如下:
class CSampleA
{
public:
CSampleA(){}
~CSampleA(){}
DestroySelf(){delete this;} //标记1
//...other member function...
};

class CFactory
{
public:
static CSampleA* GetInstanceOfA(){return new CSampleA();}
};


其中B(DLL)中有代码如下:
class CProxyA
{
public:
CProxyA(){m_pA = CFactory::GetInstanceOfA();}
~CProxyA(){if(m_pA)m_pA->DestroySelf();}
DestroySelf(){delete this;}
CSampleA* GetA(){return m_pA;}
public:
CSampleA* m_pA;
};

class CProxyFactory
{
public:
static CProxyA* GetProxyInstanceOfA(){return new CProxyA();}
};


其中C(EXE)中有代码如下:
CProxyA* pProxyA = ...; //...use CProxyFactory get CProxyA's instance
CSampleA* pA = pProxyA->GetA();
//...
//...call some CSampleA's functions...
//...
pProxyA->DestroySelf(); //release memory, then, "标注1" will have problem.


Problem:
dbgheap.c, 1252 line, _CrtIsValidHeapPointer()断言失败。

不知道我的问题描述清楚了没有。。。

//////////////////////////////////////////////////////////////////////////
问题猜想:
我感觉问题出在C和B同时都包含了A上。C和B同时有自己的堆内存空间,A分别静态链接到C和B中,那么C和B中分别包含一份A的代码段,这时,通过B的堆内存创建出来的CSampleA类,在C中调用起成员函数,是不是有问题?但为何是释放时才出问题?

请高手指点!
PS:基础不扎实或者概念比较模糊的朋友就不要误人子弟了,谢谢合作……

...全文
597 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
mister_exia 2012-04-19
  • 打赏
  • 举报
回复
CProxyA* pProxyA = ...;
这句会调用 CFactory::GetInstanceOfA();而这句会在B的CRT堆上创建对象

同理,pProxyA-> DestroySelf();这句在B的CRT堆上析构了对象

A的堆貌似没有创建,lib有模块的概念吗?跟dll是不一样的吧,dll和exe只是把lib中的代码拿过来而已啊。
  • 打赏
  • 举报
回复
我可以把我的测试代码给你,你看看,没有你说的问题。
所以肯定是其他地方引起的
MulinB 2007-08-13
  • 打赏
  • 举报
回复
本人仍存在疑问:


继续UP,期待大师详细解答。
MulinB 2007-08-13
  • 打赏
  • 举报
回复
To楼上:

你的试验并不能说明问题。
  • 打赏
  • 举报
回复
/Mtd试过了,也可以。
因为A是静态库 B和C要编译成功就必须和A是一样的 crt库。
所以new和delete是没有问题的
星羽 2007-08-11
  • 打赏
  • 举报
回复


刚刚实验了下,发想一个lib好象在进程里会确保只有一份

测试过程是

工程 1 : a.lib

只定一个变量

int handel;

工程 2 :c.lib 连接 a.lib

提供修改

handel

函数 void modify() { handel = 100; }



工程 3 :d.exe 连接 a.lib c.lib

调用 c.lib 中的

modify()

如果输出

handel

发现是 100

这个是不是说名在 d.exe 启动的进程中 a.lib 只有一份

  • 打赏
  • 举报
回复
连接器,会保证的。当然crt必须是同一个版本的。
只要能连接成功就是同一个crt,不一样的crt只会连接不成功。
星羽 2007-08-11
  • 打赏
  • 举报
回复

我有点疑问了

比如

a.exe 静态连接 crt
c.lib 静态连接 crt
a.exe 静态连接 c.lib

系统是如何确保用的是同一个crt的
  • 打赏
  • 举报
回复
b能够成功编译出来就表示 B和A使用同样的crt同样C和A 的关系也一样。
所以可以得出结论,只要你能编译出BC那么就是使用同样的crt

我已经按照你的方法试过了,是其他代码引起的问题。
marrco2005 2007-08-10
  • 打赏
  • 举报
回复
mark.
以前遇到过这样的问题,但是没有仔细研究过。只是记得一个总的原则,就是哪个模块new出来的内存,要通过该模块进行回收,否则很容易出错.
MulinB 2007-08-10
  • 打赏
  • 举报
回复
忘了说了,A/B/C三者均是以静态链接的方式使用CRT的。
MulinB 2007-08-10
  • 打赏
  • 举报
回复
up
MulinB 2007-08-10
  • 打赏
  • 举报
回复
那么C和B中分别包含一份A的代码段,这时,通过B的堆内存创建出来的CSampleA类,在C中调用起成员函数,是不是有问题?

----------------------
我觉得还是可能会有问题吧?大侠能否详细指点一下~
MulinB 2007-08-10
  • 打赏
  • 举报
回复
ABC使用的运行时库是 多线程调试(/Mtd) 吗?

后来全部换成 /Mdd 没有问题了。
  • 打赏
  • 举报
回复
没有问题,我拿你的代码测试过了
MulinB 2007-08-10
  • 打赏
  • 举报
回复
up
MulinB 2007-08-10
  • 打赏
  • 举报
回复
To akirya:

貌似问题不是您说的CRT的那个问题。

问题是:C通过B的堆内存创建出来的CSampleA类,在C中调用起成员函数,是不是有问题?

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧