Before I start, I would like to clarify two things:
I cannot use Boost IPC for this project, and I cannot use anything but original C/C++ libraries.
I have looked here and here for answers and still couldn't get the answer I wanted.
I am trying to store a vector
in shared memory location. I have mapped a shared memory page and got its pointer. I also have created the vector
itself on the shared memory using placement new
and giving it the LPVOID
of the map view:
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
BUF_SIZE, // 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;
}
pBuf = MapViewOfFile(hMapFile, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
BUF_SIZE);
if (pBuf == NULL)
{
_tprintf(TEXT("Could not map view of file (%d).\n"),
GetLastError());
CloseHandle(hMapFile);
return 1;
}
std::vector<int, shared_allocator<int>>* vec = new(pBuf) std::vector<int, shared_allocator<int>>;
Now, when I try accessing the memory from the second process, I am able to get hold of the vector
itself and even print its size()
. Obviously, I cannot access any of its data since it is all stored in the first process's heap.
From the code, it is clear I am using my custom allocator, which looks like this:
template <class T>
struct shared_allocator
{
typedef T value_type;
shared_allocator() noexcept {} //default ctor not required by C++ Standard Library
// A converting copy constructor:
template<class U> shared_allocator(const shared_allocator<U>&) noexcept {}
template<class U> bool operator==(const shared_allocator<U>&) const noexcept
{
return true;
}
template<class U> bool operator!=(const shared_allocator<U>&) const noexcept
{
return false;
}
T* allocate(const size_t n) const;
void deallocate(T* const p, size_t) const noexcept;
};
template <class T>
T* shared_allocator<T>::allocate(const size_t n) const
{
if (n == 0)
{
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
//void* const pv = malloc(n * sizeof(T));
//if (!pv) { throw std::bad_alloc(); }
//return static_cast<T*>(pv);
return (T*) ::operator new(n*sizeof(T));
}
template<class T>
void shared_allocator<T>::deallocate(T * const p, size_t) const noexcept
{
// free(p);
delete(p);
}
This code was done following Microsoft's documentation.
I replaced malloc
and free
with C++ new
and delete
. The code above works well and the first process can access everything.
Now I was trying to modify the allocator so it would allocate the newly created objects on the shared memory. So I changed the allocate
function to:
template <class T>
T* shared_allocator<T>::allocate(const size_t n) const
{
if (n == 0)
{
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
//void* const pv = malloc(n * sizeof(T));
//if (!pv) { throw std::bad_alloc(); }
//return static_cast<T*>(pv);
cnt += n*sizeof(T);
void* p = (void*) (static_cast<char*>(pBuf) + cnt);
return (T*) ::operator new(n*sizeof(T), p);
}
cnt
is a global variable that starts as 0.
This is (obviously) not working. It crashes with some memory violation exceptions and all. I tried tracking the change of cnt
and the first time it is incremented by 16, then by 4s.
The vector
is not being filled with correct data since each time the _MyFirst()
inside vector
is being replaced with an address on the shared-memory.
I know I'm doing it wrong, but I have looked in many places and cannot seem to figure out how to get it right. How do I modify my allocator
to correctly allocate on the shared-memory? If it alone can't, then would I need to re-create my own vector
?
I have been following this article and it shows that I only need to write an allocator
to make this work.