I have implemented various classes that are designed to be used in boost::interprocess
shared memory segments. All their constructors employ allocator<void,segment_manager>
references—some explicitly in the definitions I have written (like the Foo
constructor below) and some simply because that's what the boost container definition requires, in boost library code that I should not be changing (like the IndexVector
below).
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
typedef boost::interprocess::managed_shared_memory Segment;
typedef boost::interprocess::managed_shared_memory::segment_manager SegmentManager;
typedef boost::interprocess::allocator< void, SegmentManager > Allocator;
typedef size_t Index;
typedef boost::interprocess::allocator< Index, SegmentManager > IndexAllocator;
typedef boost::interprocess::vector< Index, IndexAllocator > IndexVector;
class Foo
{
public:
Foo( const Allocator & alloc ) : mData( alloc ) {}
~Foo() {}
private:
IndexVector mData;
};
Mostly, these objects sit in shared memory. But I sometimes want to create copies of them in non-shared memory. My question is this: do I have to define a whole different class (e.g. Foo_Nonshared
) containing different member types (std::vector<Index>
instead of my shared IndexVector
type) and provide copy/conversion functions between them? That will be a lot of work and a lot of stupid duplication. I could reduce duplication by providing an alternative constructor to the existing Foo
class, but then I wouldn't know how to initialize the IndexVector
member without an allocator.
Or is there some nice shortcut? I'm imagining some sort of particular allocator
instance that I can pass to Foo()
, and which will hence be passed on to the IndexVector
constructor, which will be recognized by both as meaning "allocate in non-shared memory". Does such a thing exist? Is there a "dummy segment manager" for managing vanilla non-shared memory? Or are there other ways around this problem?
I'm hoping for C++03-compatible answers even though I'm also interested to learn the C++11+ ways of doing things.
Update following question being marked as duplicate: I have read these previous similar questions:
- boost::interprocess Containers of containers NOT in shared memory
- boost::interprocess Containers of containers NOT in shared memory copy
and have tried to generalize what I see there, with some successes and some failures (see listing below). There are a few compiler errors that I haven't been able to resolve, marked ERROR—in particular I cannot figure out how to instantiate methods that iterate over the members of these highly "meta" containers. But with or without those errors, I cannot yet see how to make templates-of-templates into a maintainable solution (my objects, in reality, contain containers of other complex objects, which contain further containers, which AFAICS complicates the syntax beyond sanity... see the part marked "hmm").
I guess, in the end, I might have to re-design to avoid having the same objects in shared and heap memory.
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
namespace bip = boost::interprocess; // warning: C++11 alias declaration
template <typename T, template<typename...> class Allocator> // warning: C++11 variadic template
using Vector = bip::vector< T, Allocator<T>>; // warning: C++11 alias declaration
// this seems to work to get some of the nested <>ness under control.
// But I can't figure out how to create an iterator to this kind of type (see errors below)
// what once were classes are now class templates
template <template<typename...> class Allocator> // warning: C++11 variadic template
class Bar
{
public:
Bar( const Allocator<void> & alloc ) : mInts( alloc ) {}
~Bar() {}
void Report( void );
private:
Vector< int, Allocator > mInts;
};
template <template<typename...> class Allocator> // warning: C++11 variadic template
class Foo
{
public:
Foo( const Allocator<void> & alloc ) : mBars( alloc ) {}
~Foo() {}
void Report( void );
private:
Vector< Bar<Allocator>, Allocator > mBars; // hmm, with more complex structures this is going
// to get unmanageably< nested< very< quickly > > > ...
};
// Define allocator templates
template <typename T>
using HeapAllocator = std::allocator<T>; // warning: C++11 alias declaration
template <typename T>
using ShmemAllocator = bip::allocator<T, bip::managed_shared_memory::segment_manager>; // warning: C++11 alias declaration
// Define two class variants: one for use on the heap and one for use in shared memory
using HeapFoo = Foo< HeapAllocator >; // warning: C++11 alias declaration
using ShmemFoo = Foo< ShmemAllocator >; // warning: C++11 alias declaration
// Try to define methods (unsuccessful so far because of the iterators,
// but they compile OK if the function bodies are left empty):
template <template<typename...> class Allocator> // warning: C++11 variadic template
void
Bar< Allocator >::Report( void )
{
std::cout << "[";
Vector< int, Allocator >::iterator it;
// ERROR: ^~~~~ expected ';' after expression
for( it = mInts.begin(); it += mInts.end(); it++ )
std::cout << ( it == mInts.begin() ? "" : ", " ) << *it;
std::cout << "]\n";
}
template <template<typename...> class Allocator> // warning: C++11 variadic template
void
Foo< Allocator >::Report( void )
{
Vector< Bar< Allocator >, Allocator >::iterator it;
// ERROR: ^~~~~ expected ';' after expression
for( it = mBars.begin(); it += mBars.end(); it++ )
it->Report();
std::cout << "\n";
}
int main( void )
{
struct shm_remove
{
shm_remove() { bip::shared_memory_object::remove( "MySharedMemory" ); }
~shm_remove() { bip::shared_memory_object::remove( "MySharedMemory" ); }
} remover;
bip::managed_shared_memory seg( bip::create_only, "MySharedMemory", 65536 );
ShmemAllocator< void > shalloc( seg.get_segment_manager() );
HeapAllocator< void > halloc;
HeapFoo foo1( halloc );
ShmemFoo foo2( shalloc );
foo1.Report();
foo2.Report();
}