【发布时间】:2015-02-14 00:39:18
【问题描述】:
我已经实现了各种设计用于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;
};
大多数情况下,这些对象位于共享内存中。但我有时想在 非 共享内存中创建它们的副本。我的问题是:我是否必须定义一个包含不同成员类型(std::vector<Index> 而不是我共享的IndexVector 类型)的完全不同的类(例如Foo_Nonshared)并在它们之间提供复制/转换功能?这将是很多工作和很多愚蠢的重复。我可以通过为现有的Foo 类提供替代构造函数来减少重复,但是我不知道如何在没有分配器的情况下初始化IndexVector 成员。
或者有什么不错的捷径?我在想象某种特定的allocator 实例,我可以将其传递给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();
}
【问题讨论】:
-
另请参阅 followup 以获取相关想法的欺骗问题
-
嗯,是的,我看到了那些线程。我了解您对第一个答案的语言/概念,但在后续行动中遇到了困难,尤其是 OP 的评论和对它的回答(“推断函数模板中的参数,并分派到您专门针对不同的函数对象实际参数类型”完全超出了我的理解水平)。在第一个中,似乎工作必须手动和步行完成,逐个成员复制:这是我希望通过“虚拟”部门经理避免的事情(但我想不存在这样的事情)。
-
在第二个线程中,该解决方案似乎非常特定于容器类(即那些实现
assign、begin和end的容器类)。我想我需要实现特定于分配的方法来完成我的Foo<Allocator>和Foo<std::allocator>之间的转换工作。 -
关于理解第一个线程,我说得太早了。 “为分配器类模板模板化”和
template <template<typename...> class Allocator>需要进行一些研究才能了解这里发生了什么。 -
重新开放:对于更复杂的类,甚至无法进行复制操作。
标签: c++ boost shared-memory