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关联容器对象。同理不同进程之间也不能。
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关联容器对象。同理不同进程之间也不能。