在 C++ 中,结构中的 std::list 如何分配内存,而在文件映射中使用它时,列表结果为空
In C++, How std::list in a struct will allocate memory and while using this in file mapping, the list result as empty
面临的问题:
使用文件映射共享的列表不提供列表内的任何数据...
我有一个进程 1,其中我将所有数据存储为 hash_map 的列表,然后我尝试使用文件映射共享它...在 Process2 中,同时我尝试检索其中的数据列表,在列表中找不到数据..
PS: 我的 exe 与 dll 捆绑在一起,我将我的 dll 作为 process1,将 exe 作为 process2...
这是我的代码,
Process1
/* this is in common headerFile */
typedef hash_map <std::wstring,std::wstring> AttrValues;
CString FileName = L"E:\DataLog.txt";
TCHAR szName[]=TEXT("Local\MyFileMappingObject");
struct ADstruct
{
std::list<AttrValues> StList;
int i;
};
/*Sharememory.cpp*/
DWORD SharedMemory()
{
AttrValues HardCode;//Sample data which i am hard coding for testing
HardCode[L"NAme"] = L"Test";
HardCode[L"D.Name"] = L"SAP";
std::list <AttrValues> HardCodedList;
HardCodedList.push_back(HardCode);
ADstruct CheckStruct;
CheckStruct.i = 10;
CheckStruct.StList = HardCodedList;
HANDLE hFile = INVALID_HANDLE_VALUE;// HANDLE hFile;
hFile = CreateFile(FileName.GetBuffer(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("Error in creating a file..!");
return 0;
}
hMapFile = CreateFileMapping(
hFile, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
sizeof(ADstruct), // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
ADstruct *ADobj = new ADstruct;
ADobj = (ADstruct *) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(ADstruct) );
CopyMemory( (ADstruct *) ADobj, &CheckStruct , sizeof(ADstruct) );
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0
}
Process 2:
BOOL ReadMemoryMapping()
{
hash_map<LPWSTR,LPWSTR> ADdata;
HANDLE hMapFile;
HANDLE hFile = INVALID_HANDLE_VALUE;
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
ADstruct * readstruct;
readstruct = (ADstruct *) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(ADstruct));
_tprintf(L"\nprint data%d\n",readstruct->i);
AttrValues At ;
for(std::list<AttrValues>::iterator list_iter = readstruct->StList.begin();
list_iter != readstruct->StList.end(); list_iter++)
{
At.clear();
At = *list_iter; //*****Here the code crashes as there is no datas inside***
if(At.empty() == 1)
printf("List is empty\n");
std::wcout<<endl<<endl<<"Attribute List In EXE : StList"<<endl;
for(AttrValues :: iterator it1 = list_iter->begin(); it1!= list_iter->end(); it1++)
{
std::wcout<<it1->first<<endl;
std::wcout<<it1->second<<endl;
}
}
UnmapViewOfFile(readstruct);
CloseHandle(hMapFile);
return 0;
}
首先,正则std::list
是一个多级数据结构,它包含对地址space中其他位置的引用。实际的列表元素不存储在 std::list
对象中。它们存储在内存中的其他地方。而 std::list
只是通过指针引用这些元素。您的文件映射只是共享顶级 std::list
对象,但它甚至不会尝试共享实际的列表元素。
其次,即使您以某种方式设法神奇地确定并共享地址 space 的整个区域,其中包含与您的 std::list
相关的所有内容,它仍然无法正常工作,除非您以某种方式确保在内存映射到地址 space 中完全相同区域的所有进程。这适用于任何使用指针的数据结构。
也就是说,做不到。您不能只获取现有的普通 std::list
并通过内存映射共享它。
事实上,您尝试使用 CopyMemory
等函数复制非平凡对象(如 std::list
)可能已经足以破坏对象的完整性。不需要涉及内存映射。
你可以改变。标准库模板为:
template<class T, class Allocator = std::allocator<T> > class list;
因此,如果需要,您可以提供自己的内存分配器作为第二个模板参数。如果您使用默认的,基本上是 new
,它会从堆中分配节点,这些节点不会在共享内存中。 (这似乎是您使用内存映射文件的方式。)另一个进程将能够读取每个列表的头部,但不能读取分配在任何地方的其余节点。
但是,您可以改为在共享内存中分配一个节点池,然后编写您自己的分配器来分配共享内存块,直到它消失为止。 (如果每个共享内存块都是可重用的,则共享内存可以是它自己的迷你堆。但是,如果您可以在完成所有列表后同时删除它们,那么取消映射就足够了共享内存块。)
或者您可以编写自己的列表 class,该列表使用共享内存中节点池中的索引,而不是指针,这是一种存储在文件中实际上具有潜在意义的布局。或者您可以在共享内存中静态分配一个 std::array
。它的所有存储都在 class 对象本身内部,并且它的大小是固定的,因此它不会在共享块之外分配任何内存,并且可以开箱即用。
面临的问题: 使用文件映射共享的列表不提供列表内的任何数据...
我有一个进程 1,其中我将所有数据存储为 hash_map 的列表,然后我尝试使用文件映射共享它...在 Process2 中,同时我尝试检索其中的数据列表,在列表中找不到数据..
PS: 我的 exe 与 dll 捆绑在一起,我将我的 dll 作为 process1,将 exe 作为 process2...
这是我的代码,
Process1
/* this is in common headerFile */
typedef hash_map <std::wstring,std::wstring> AttrValues;
CString FileName = L"E:\DataLog.txt";
TCHAR szName[]=TEXT("Local\MyFileMappingObject");
struct ADstruct
{
std::list<AttrValues> StList;
int i;
};
/*Sharememory.cpp*/
DWORD SharedMemory()
{
AttrValues HardCode;//Sample data which i am hard coding for testing
HardCode[L"NAme"] = L"Test";
HardCode[L"D.Name"] = L"SAP";
std::list <AttrValues> HardCodedList;
HardCodedList.push_back(HardCode);
ADstruct CheckStruct;
CheckStruct.i = 10;
CheckStruct.StList = HardCodedList;
HANDLE hFile = INVALID_HANDLE_VALUE;// HANDLE hFile;
hFile = CreateFile(FileName.GetBuffer(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("Error in creating a file..!");
return 0;
}
hMapFile = CreateFileMapping(
hFile, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
sizeof(ADstruct), // maximum object size (low-order DWORD)
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not create file mapping object (%d).\n"),
GetLastError());
return 1;
}
ADstruct *ADobj = new ADstruct;
ADobj = (ADstruct *) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(ADstruct) );
CopyMemory( (ADstruct *) ADobj, &CheckStruct , sizeof(ADstruct) );
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
return 0
}
Process 2:
BOOL ReadMemoryMapping()
{
hash_map<LPWSTR,LPWSTR> ADdata;
HANDLE hMapFile;
HANDLE hFile = INVALID_HANDLE_VALUE;
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS, // read/write access
FALSE, // do not inherit the name
szName); // name of mapping object
if (hMapFile == NULL)
{
_tprintf(TEXT("Could not open file mapping object (%d).\n"),
GetLastError());
return 1;
}
ADstruct * readstruct;
readstruct = (ADstruct *) MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
sizeof(ADstruct));
_tprintf(L"\nprint data%d\n",readstruct->i);
AttrValues At ;
for(std::list<AttrValues>::iterator list_iter = readstruct->StList.begin();
list_iter != readstruct->StList.end(); list_iter++)
{
At.clear();
At = *list_iter; //*****Here the code crashes as there is no datas inside***
if(At.empty() == 1)
printf("List is empty\n");
std::wcout<<endl<<endl<<"Attribute List In EXE : StList"<<endl;
for(AttrValues :: iterator it1 = list_iter->begin(); it1!= list_iter->end(); it1++)
{
std::wcout<<it1->first<<endl;
std::wcout<<it1->second<<endl;
}
}
UnmapViewOfFile(readstruct);
CloseHandle(hMapFile);
return 0;
}
首先,正则std::list
是一个多级数据结构,它包含对地址space中其他位置的引用。实际的列表元素不存储在 std::list
对象中。它们存储在内存中的其他地方。而 std::list
只是通过指针引用这些元素。您的文件映射只是共享顶级 std::list
对象,但它甚至不会尝试共享实际的列表元素。
其次,即使您以某种方式设法神奇地确定并共享地址 space 的整个区域,其中包含与您的 std::list
相关的所有内容,它仍然无法正常工作,除非您以某种方式确保在内存映射到地址 space 中完全相同区域的所有进程。这适用于任何使用指针的数据结构。
也就是说,做不到。您不能只获取现有的普通 std::list
并通过内存映射共享它。
事实上,您尝试使用 CopyMemory
等函数复制非平凡对象(如 std::list
)可能已经足以破坏对象的完整性。不需要涉及内存映射。
你可以改变。标准库模板为:
template<class T, class Allocator = std::allocator<T> > class list;
因此,如果需要,您可以提供自己的内存分配器作为第二个模板参数。如果您使用默认的,基本上是 new
,它会从堆中分配节点,这些节点不会在共享内存中。 (这似乎是您使用内存映射文件的方式。)另一个进程将能够读取每个列表的头部,但不能读取分配在任何地方的其余节点。
但是,您可以改为在共享内存中分配一个节点池,然后编写您自己的分配器来分配共享内存块,直到它消失为止。 (如果每个共享内存块都是可重用的,则共享内存可以是它自己的迷你堆。但是,如果您可以在完成所有列表后同时删除它们,那么取消映射就足够了共享内存块。)
或者您可以编写自己的列表 class,该列表使用共享内存中节点池中的索引,而不是指针,这是一种存储在文件中实际上具有潜在意义的布局。或者您可以在共享内存中静态分配一个 std::array
。它的所有存储都在 class 对象本身内部,并且它的大小是固定的,因此它不会在共享块之外分配任何内存,并且可以开箱即用。