Using Boost flyweight with shared memory

644 views Asked by At

I'd like to keep a large number of (frequently duplicated) strings in shared-memory, so I'm using Boost's flyweight and interprocess basic_string functionality. To ensure that the string is actually stored in the shared-memory, I need to supply a custom allocator in the hashed_factory used by the flyweight.

However, that fails to compile (g++ 4.2.1) when I specify my custom allocator to hashed_factory... probably because it requires an extra argument to specify the segment manager. What's the syntax to get this working, or is there a better way to do this?

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/flyweight.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/flyweight/hashed_factory.hpp>

using namespace boost::flyweights;
using namespace boost::container;
using namespace boost::interprocess;


typedef boost::interprocess::allocator<boost::mpl::_1, boost::interprocess::managed_mapped_file::segment_manager> ShmFactoryEntryAllocator;

typedef boost::interprocess::allocator<char, boost::interprocess::managed_mapped_file::segment_manager> ShmAllocatorChar;

typedef boost::interprocess::basic_string<char, std::char_traits<char>, ShmAllocatorChar> ShmString;

// TODO: using ShmFactoryEntryAllocator does not work
typedef boost::flyweights::hashed_factory<boost::hash<ShmString>, std::equal_to<ShmString>, ShmFactoryEntryAllocator> ShmStringHashedFactory;
//typedef boost::flyweights::hashed_factory<boost::hash<ShmString>, std::equal_to<ShmString>, std::allocator<boost::mpl::_1> > ShmStringHashedFactory;

// TODO: need to be able to use a hashed_factory with our custom allocator.
typedef boost::flyweights::flyweight<ShmString, ShmStringHashedFactory> ShmFlyweightString;
//typedef boost::flyweights::flyweight<ShmString> ShmFlyweightString;


int main(int argc, char** argv)
{
    managed_mapped_file *segment = new managed_mapped_file(create_only, "memory.dat", 409600);
    ShmFactoryEntryAllocator factoryEntryAllocator(segment->get_segment_manager());

    // create a normal string in shared-memory.
    ShmString *ps1 = segment->construct<ShmString>("s1")("some shm normal string", factoryEntryAllocator);

    // create a flyweight string in shared memory.
    ShmFlyweightString *ps2 = segment->construct<ShmFlyweightString>(anonymous_instance)("some shm flyweight string", factoryEntryAllocator);

    return 0;
}

The lines after the TODO comments are the problematic lines, with the commented versions being the ones that work but do not use the correct allocator.

1

There are 1 answers

2
rhashimoto On BEST ANSWER

It looks like you're right about the problem being the required constructor argument. The hashed_factory docs say:

The internal hashed container upon which hashed_factory_class is based is constructed with default initialized objects of type Hash, Pred and Allocator.

I wonder if you can work around this by making a subclass of the shared memory allocator that has a default constructor, passing the segment manager to the base class constructor. For example, something like this:

class MyShmAllocator : public ShmFactoryEntryAllocator {
public:
  static boost::interprocess::managed_mapped_file::segment_manager *segmentManager;

  MyShmAllocator()
  : ShmFactoryEntryAllocator(*segmentManager) {
  }
};

You would need to assign a "current" MyShmAllocator::segmentManager before any call to the constructor. It's a little ugly but I think it should work.