DLL里为什么不能返回一个map对象

yfish 2003-11-13 09:38:13
我发现DLL里的函数new的东西,不能在调用DLL的进程里delete,反之亦然。
这似乎不合逻辑。但却是真的
DLL:
int * create(){
return new int(1);
}

EXE:
int * pi=create();
delete pi;//ERROR!!!



DLL:
void release(int * pi){
delete pi;//ERROR!!!!!
}

EXE:
release(new int(1));



另外,我在DLL里返回map<string,string>类型的东西,调用DLL的进程却不能接受它,像这样:
DLL:
map<string,string>* getData(){
map<string,string>* pm;
pm->insert(pair<string,string>("1","1"));
}

EXE:
map<string,string>* pm=getData();
map<string,string> m =*pm;//ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
map<string,string>::iterator iter=pm->begin();
while(iter != pm->end())
{
cout << (*iter).first ; //OK,output "1"
iter++;//ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}

并不是所有的元素都不能访问,只是最后一个元素的后一个元素不行。
...全文
282 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
yfish 2003-11-14
  • 打赏
  • 举报
回复
map的问题总算找到答案了,我刚查了一下gcc带的STL,里面的终止节点不是静态的,没有这个问题。
yfish 2003-11-14
  • 打赏
  • 举报
回复
在DLL与EXE之间传递STL容器对象的问题总结

exemple1
DLL:
insert(vector<string>* pvstr)
{
vstr->push_back("111");
}

EXE:
{
vector<string> vstr;
insert(&vstr);
}//ERROR1

解释:
EXE和DLL都有自己堆,所以在DLL里动态创建的东西,不能在调用DLL的进程里销毁,反之亦然。
上面的insert()在DLL堆里创建了string对象,而销毁这个对象的动作发生在EXE进程里,即vstr的析构。

exemple2
DLL:
foo1(vector<string> vstr)
{
return;
}

vector<string>foo2()
{
vector<string> vstring;
return vstring;
}

EXE:
{
vector<string> vstring;
foo1(vstring);//ERROR2
vstring=foo2();

}//ERROR3

错误的根本原因与exemple1相同,
ERROR2是因为vstring在EXE进程空间产生了一个vstring临时的副本vstr。这个副本引用了EXE空间分配的内存块,
但vstr却属于DLL里的foo1()的局部变量。当foo1()退出时,vstr析构。vstr在试图释放先前的内存块时,发生异常。
ERROR3和ERROR2类似,只不过这次临时变量实在DLL中产生而在EXE中销毁。

基于以上两点,DLL和EXE之间不能对有引用动态内存块成员变量的对象进行值传递,只能传指针或引用。
而且对传过来的对象不能进行可导致内存释放或重新分配的修改。

但下面这个例子,虽然是传指针并且是只读访问,但也有错误。

exemple3

DLL:
map<int,int>* getData(){
map<int,int>* pm=new map<int,int>();
pm->insert(pair<string,string>(1,1));
return pm;
}

EXE:
map<int,int>* pm=getData();
map<int,int> m =*pm;//ERROR4
map<int,int>::iterator iter=pm->begin();
while(iter != pm->end())
{
cout << (*iter).first ; //OK,output "1"
iter++;//ERROR5
}

上面的错误在与STL的实现有关,我采用的是VC带的STL。里面的关联容器都使用一个叫_Tree的类,_Tree的空节点指针被定义一个
静态的成员函数:
xtree:424 static _Nodeptr _Nil;
_Nil被当成关联容器的最后一个节点。但由于_Nil是静态的,所以一个进程空间只有一个_Nil节点。而DLL和EXE中的_Nil节点是不一样的。
当在EXE中遍历DLL创建的map对象时,会把DLL中的_Nil节点和EXE中的_Nil节点以确定是否到达最后一个节点。它们永远不会相等,也就找不到终止节点直到访问到非法地址空间而出错。

也就是说,动态连接库和调用动态连接库的进程之间,不能互访STL关联容器对象。同理不同进程之间也不能。


以上例子基于VC6.0
vcforever 2003-11-13
  • 打赏
  • 举报
回复
如果在DLL中调用了new那么在这个DLL中相应的一定要调用delete!

迭代器pm->end()指向的是这个容器最后一个元素后面的位置,iter++;//ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
这句可能是越界造成的,试着把界限缩小一个元素试一试呢!参考一下!
双杯献酒 2003-11-13
  • 打赏
  • 举报
回复
DLL里的函数new的东西,不能在调用DLL的进程里delete

这个是DLL的基础知识之一。

15,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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