I have implemented various classes that are designed to be used in boost::interprocess
shared memory segments. All their constructors employ allocator<
Ok, you've run into the Frequently Annoying Edgecase that template-template arguments aren't first class citizens in C++ (you cannot pass them around/typedef them):
What shall we do?
allocator::rebind<T>
Allocators have a rebind mechanism, I daresay precisely because of this. So you can pass a alloc<void>
as if it is the open template, because you can always get from there to a sibling allocator type by doing Alloc::rebind<T>::other
.
Add to this the fact that allocators usually have conversion constructors that do this rebinding, you don't need to be overly specific in many places taking allocators
in c++11, scoped_allocator
s have been introduced to avoid having to manually pass allocator
instances in a number of places that will do internal construction of elements (e.g. emplace_back
).
There's library magic in place that will automatically add the allocator instance from the container's scoped_allocator
as the last constructor argument (by default). Boost Container library has backported the scoped_allocator_adaptor
concept to c++03 so you can use it.
Here's a full sample that shows you how to solve the issues you had, and also, how you can mix the heap-based Bar
instances with the shared-memory Foo
instance:
foo2.add(bar1); // this works because of ... MAGIC!
Which works due to the scoped_allocator
mentioned above.
Live On Coliru
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/container/scoped_allocator.hpp>
namespace bip = boost::interprocess;
namespace generic {
template <typename T, typename Alloc/* = std::allocator<T>*/ >
using vector = bip::vector<T, typename Alloc::template rebind<T>::other >;
template <typename Alloc> struct Bar {
typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator
// only require allocator if not default-constructible
Bar(Alloc alloc = Alloc()) : mInts(alloc) {}
// conversion constructor so we can convert between allocators
template <typename OtherAlloc>
Bar(Bar<OtherAlloc> const& rhs, Alloc alloc = Alloc())
: mInts(rhs.mInts.begin(), rhs.mInts.end(), alloc)
{
}
void Report() const;
void add(int i) { mInts.emplace_back(i); }
private:
template<typename OtherAlloc> friend struct Bar; // we can see each other's mInts
typedef vector<int, Alloc> ints_t;
ints_t mInts;
};
template <typename Alloc> struct Foo {
typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator
Foo(Alloc alloc = Alloc()) : mBars(alloc) {}
void Report() const;
template <typename Bar>
void add(Bar const& bar) { mBars.emplace_back(bar); }
private:
typedef vector<Bar<Alloc>, Alloc> mbars_t;
mbars_t mBars;
};
}
namespace heap {
using VAlloc = std::allocator<void>;
using Bar = generic::Bar<VAlloc>;
using Foo = generic::Foo<VAlloc>;
}
namespace shared {
using VAlloc = boost::container::scoped_allocator_adaptor<bip::allocator<void, bip::managed_shared_memory::segment_manager> >;
using Bar = generic::Bar<VAlloc>;
using Foo = generic::Foo<VAlloc>;
}
template <typename Alloc> void generic::Bar<Alloc>::Report() const {
std::cout << "[";
for (typename ints_t::const_iterator it = mInts.begin(); it != mInts.end(); it++)
std::cout << (it == mInts.begin() ? "" : ", ") << *it;
std::cout << "]\n";
}
template <typename Alloc>
void generic::Foo<Alloc>::Report() const {
for (typename mbars_t::const_iterator 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;
///////////////////////////////////
// heap based:
std::cout << "Heap based storage: \n";
heap::Foo foo1;
heap::Bar bar1;
bar1.add(42);
bar1.add(2);
bar1.add(-99);
foo1.add(bar1);
foo1.Report();
/////////////////////////////////
std::cout << "Shared memory storage: \n";
bip::managed_shared_memory seg(bip::create_only, "MySharedMemory", 65536);
shared::VAlloc shalloc(seg.get_segment_manager());
shared::Foo foo2(shalloc);
shared::Bar bar2(shalloc);
bar2.add(43);
bar2.add(3);
bar2.add(-98);
foo2.add(bar2); // of course this works
foo2.add(bar1); // this works because of ... MAGIC!
foo2.Report();
}
Prints:
Heap based storage:
[42, 2, -99]
Shared memory storage:
[43, 3, -98]
[42, 2, -99]