Hi,
After combing through the Boost::Interprocess documentation and Google searches, I think I've found the reason/workaround to my issue. Everything I've found, as I understand it, seems to be hinting at this, but doesn't come out and say "do this because...". But if anyone can verify this I would appreciate it.
I'm writing a series of classes that represent a large lookup of information that is stored in memory for fast performance in a parallelized application. Because of the size of data and multiple processes that run at a time on one machine, we're using Boost::Interprocess for shared memory to have a single copy of the structures.
I looked at the Boost::Interprocess documentation and examples, and they typedef classes for shared memory strings, string vectors, int vector vectors, etc. And when they "use" them in their examples, they just construct them passing the allocator and maybe insert one item that they've constructed elsewhere. Like on this page: http://www.boost.org/doc/libs/1_42_0/doc/html/interprocess/allocators_containers.html
So following their examples, I created a header file with typedefs for shared memory classes:
namespace shm {
namespace bip = boost::interprocess;
// General/Utility Types
typedef bip::managed_shared_memory::segment_manager segment_manager_t;
typedef bip::allocator<void, segment_manager_t> void_allocator;
// Integer Types
typedef bip::allocator<int, segment_manager_t> int_allocator;
typedef bip::vector<int, int_allocator> int_vector;
// String Types
typedef bip::allocator<char, segment_manager_t> char_allocator;
typedef bip::basic_string<char, std::char_traits<char>, char_allocator> string;
typedef bip::allocator<string, segment_manager_t> string_allocator;
typedef bip::vector<string, string_allocator> string_vector;
typedef bip::allocator<string_vector, segment_manager_t> string_vector_allocator;
typedef bip::vector<string_vector, string_vector_allocator> string_vector_vector;
}
Then for one of my lookup table classes, it's defined something like this:
class Details {
public:
Details(const shm::void_allocator & alloc) :
m_Ids(alloc),
m_Labels(alloc),
m_Values(alloc) {
}
~Details() {}
int Read(BinaryReader & br);
private:
shm::int_vector m_Ids;
shm::string_vector m_Labels;
shm::string_vector_vector m_Values;
};
int Details::Read(BinaryReader & br) {
int num = br.ReadInt();
m_Ids.resize(num);
m_Labels.resize(num);
m_Values.resize(num);
for (int i = 0; i < num; i++) {
m_Ids[i] = br.ReadInt();
m_Labels[i] = br.ReadString().c_str();
int count = br.ReadInt();
m_Value[i].resize(count);
for (int j = 0; j < count; j++) {
m_Value[i][j] = br.ReadString().c_str();
}
}
}
But when I compile it, I get the error:
'boost::interprocess::allocator<T,SegmentManager>::allocator' : no appropriate default constructor available
And it's due to the resize() calls on the vector objects. Because the allocator types do not have a empty constructor (they take a const segment_manager_t &) and it's trying to create a default object for each location. So in order for it to work, I have to get an allocator object and pass a default value object on resize. Like this:
int Details::Read(BinaryReader & br) {
shm::void_allocator alloc(m_Ids.get_allocator());
int num = br.ReadInt();
m_Ids.resize(num);
m_Labels.resize(num, shm::string(alloc));
m_Values.resize(num, shm::string_vector(alloc));
for (int i = 0; i < num; i++) {
m_Ids[i] = br.ReadInt();
m_Labels[i] = br.ReadString().c_str();
int count = br.ReadInt();
m_Value[i].resize(count, shm::string(alloc));
for (int j = 0; j < count; j++) {
m_Value[i][j] = br.ReadString().c_str();
}
}
}
Is this the best/correct way of doing it? Or am I missing something.
Thanks!