在dll导出函数参数中传递map类型的参数,在函数内insert时出非法访问错

fwdever 2003-01-26 05:31:31

AFX_EXT_API void test(map<string, int> p_tmTest)
{
string l_strTest = "test";
p_tmTest.insert(make_pair(l_strTest, 1));

}
在执行到insert时就出非法访问错,但在本DLL内调用则没有问题,在其它Exe或DLL导入此函数,调用它就不行了,请高手指点
...全文
226 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
searoc 2003-02-12
  • 打赏
  • 举报
回复
楼上人员只有test422说的还在理,这个问题我早就发现了,而且整理了一下。请仔细看看下面的文档:
在多个DLL(exe)之间通过指针或者引用传递STL对象时会发现操作失败现象。MSDN上给出了完整的解决方法。在开发应用程序的过程中需要认真对待。

现象:

在不同的DLL或EXE中通过指针或引用操作另一个DLL或EXE中的STL对象时,会遇到严重的程序错误,包括数据错乱或丢失。

原因:

标准C++库的多数类直接或间接的使用了静态数据成员。由于这些类是通过模板创建实例的,所以每个可执行程序(一般是有DLL或EXE扩展名的)包含了有关类静态数据成员的一份Copy。当STL类中的方法要求操作静态数据成员时,这个类操作的静态数据是此方法代码所在的执行程序中的数据。由于静态成员数据在可执行程序中不能保证同步,所以前面提到的操作会导致读取失败或数据混乱和丢失。

解决方法:

1. 在创建STL对象的可执行程序中输出读取的方法(函数)。这些函数包装STL对象要求的功能。这样,STL对象只能在单个可执行程序中被直接读取。例如:假设MyProgram.EXX需要得到MyLibrary.DLL 内deque<MyClass >中的下一个元素,MyLibrary.DLL则要输出读取方法:“MyClass* DequeNextItem (/*...*/);”。MyProgram.EXE就可以执行此方法来得到队列的下一个元素了。
2. 从一个可执行程序中输出模板实例,在另一个可执行程序中引入此实例。例如:MyLibrary.DLL将vector<MyClass>指针回传给MyProgram.EXE中的一个函数,需要在MyLibrary.DLL中输出MyClass类和vector<MyClass>。在MyProgram.EXE中引入它们后。就可以得到MyLibrary.DLL中静态数据成员的一份Copy了。

例子程序:
//---------------------------------------------------------
// AVEXE.CPP
// Compile options needed: /GX
#pragma warning (disable : 4786)
#include <map>
#include <string>
#include <stdio.h>
__declspec(dllimport) std::map<int,std::string>* GiveMeAMap(int n);
__declspec(dllimport) void ShowMeTheMap(std::map<int,std::string> *amap);
__declspec(dllexport) const char* MapItemX (std::map<int,std::string> *m, int x);
int main () {
// Create the map in the DLL
int x = 6;
std::map<int,std::string> *p = GiveMeAMap(x);

// Display the contents of the map from the DLL
printf("Showing contents from the DLL\n");
ShowMeTheMap(p);

// Display the contents of the map from the EXE
// using the accessor function from the DLL so we
// aren't directly accessing the map
printf("Showing contents from the EXE using accessor\n");
int i = x;
while (i--) {
printf("%d = %s\n",i,MapItemX(p,i));
}

// Access Violation when accessing the map that
// was created in the DLL from the EXE
printf("Showing contents from the EXE directly\n");
while (x--) {
printf("%d = %s\n",x,(*p)[x].c_str());
}

return 0;
}

//---------------------------------------------------------
// AVDLL.CPP
// Compile options needed /GX
#pragma warning (disable : 4786)
#include <map>
#include <string>
#include <stdlib.h>

// Create the map here in the DLL
__declspec(dllexport) std::map<int,std::string>* GiveMeAMap(int n)
{
std::map<int,std::string> *m = new std::map<int,std::string>;
while(n--) {
char b[33];
itoa(n,b,2);
(*m)[n] = std::string(b);
}
return m;
}

// We can access the map without error from the executable
// image where the map was created
__declspec(dllexport) void ShowMeTheMap(std::map<int,std::string> *p)
{
int x = p->size();
while (x--) {
printf("%d = %s\n",x,(*p)[x].c_str());
}
}

// An accessor method to return the associated C string
// for key x
__declspec(dllexport) const char* MapItemX (std::map<int,std::string> *m, int x)
{
return (*m)[x].c_str();
}
oustar 2003-02-11
  • 打赏
  • 举报
回复
主要是参数传递的问题。
good luck!
taowen2002 2003-02-08
  • 打赏
  • 举报
回复
用一个interface比较好
————————————
taowen.cn.st
test422 2003-02-07
  • 打赏
  • 举报
回复
STL中的容器不能从VC++中的DLL中引出。
如果引出后其结果是不可预期错误。
如果一定要引出,建议引出一个类指针(或引用),然后用这个类中的方法封装你要操作的容器方法即可!
  • 打赏
  • 举报
回复
这是虚拟内存的事,与你的dll没有关系的!你的map传递的是一个地址,而它只在本地进程地址空间内有效,是个逻辑地址值,被其他进程调用当然是非法了:)
可以考虑使用WM_COPYDATA消息传递map或直接用内存映射文件。用sendmessage()好象也行,但是个诡异的用法:)
fwdever 2003-01-27
  • 打赏
  • 举报
回复
是我打错了,我用的是引用
AFX_EXT_API void test(map<string, int>& p_tmTest)
现在问题应当是C运行库有多个Copy存在,但我确实都是用的/MDD编译选项。
merlinran 2003-01-26
  • 打赏
  • 举报
回复
1、参数传递方式不一样。
2、多线程访问
我假想的可能情况。你需要对dll有多一些理解才能解决这个问题。
Cybergate 2003-01-26
  • 打赏
  • 举报
回复
我不懂dll,但是我有个建议:把参数改为传引用.否则这个过程似乎什么都没做.

估计不行......

24,854

社区成员

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

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