c – 制作boost :: interprocess共享内存对象的非共享副本
作者:互联网
我已经实现了各种旨在用于boost :: interprocess共享内存段的类.他们所有的构造函数都使用allocator< void,segment_manager>引用 – 一些显式在我编写的定义中(如下面的Foo构造函数),有些只是因为这是boost容器定义所需要的,在boost库代码中我不应该改变(如下面的IndexVector).
#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;
};
大多数情况下,这些对象位于共享内存中.但我有时想在非共享内存中创建它们的副本.我的问题是:我是否必须定义一个包含不同成员类型的整个不同的类(例如Foo_Nonshared)(std :: vector< Index>而不是我的共享IndexVector类型)并在它们之间提供复制/转换功能?这将是很多工作和很多愚蠢的重复.我可以通过为现有的Foo类提供替代构造函数来减少重复,但后来我不知道如何在没有分配器的情况下初始化IndexVector成员.
还是有一些不错的捷径?我正在想象我可以传递给Foo()的某种特定的分配器实例,因此它将传递给IndexVector构造函数,它将被两者识别为“在非共享内存中分配”.这样的事情存在吗?是否存在用于管理香草非共享内存的“虚拟段管理器”?或者还有其他解决这个问题的方法吗?
我希望能够获得C 03兼容的答案,尽管我也有兴趣学习C 11的做法.
更新以下问题被标记为重复:我已阅读以前类似的问题:
> boost::interprocess Containers of containers NOT in shared memory
> boost::interprocess Containers of containers NOT in shared memory copy
并试图概括我在那里看到的东西,有一些成功和一些失败(见下面的清单).有一些我无法解决的编译器错误,标记为ERROR-特别是我无法弄清楚如何实例化迭代这些高度“元”容器成员的方法.但无论有没有这些错误,我还不知道如何将模板模板制作成可维护的解决方案(实际上,我的对象包含其他复杂对象的容器,其中包含更多容器,AFAICS使语法复杂化,超越了理智. ..看到标有“嗯”的部分).
我想,最后,我可能不得不重新设计,以避免在共享和堆内存中使用相同的对象.
#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();
}
解决方法:
好吧,你已经遇到了频繁烦人的边缘情况,模板模板参数不是C中的一等公民(你不能传递它们/ typedef它们):
我们该怎么办?
> allocator :: rebind< T>
分配器具有重新绑定机制,我敢说正是因为这个原因.所以你可以传递一个alloc< void>好像它是打开的模板,因为你总是可以通过Alloc :: rebind< T> :: other从那里获得兄弟分配器类型.
>除此之外,分配器通常具有执行此重新绑定的转换构造器这一事实,您不需要在分配器的许多地方过于具体
>在c 11中,引入了scoped_allocators以避免必须在多个将执行元素内部构造的地方手动传递分配器实例(例如emplace_back).
有适当的库魔法,会自动将容器的scoped_allocator中的allocator实例添加为最后一个构造函数参数(默认情况下). Boost Container库已将scoped_allocator_adaptor概念向后移植到c 03,因此您可以使用它.
这是一个完整的示例,向您展示如何解决您遇到的问题,以及如何将基于堆的Bar实例与共享内存Foo实例混合:
foo2.add(bar1); // this works because of ... MAGIC!
由于上面提到的scoped_allocator,它的工作原理.
#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();
}
打印:
Heap based storage:
[42, 2, -99]
Shared memory storage:
[43, 3, -98]
[42, 2, -99]
标签:c,boost,shared-memory 来源: https://codeday.me/bug/20190929/1830957.html