要有效地克服密钥类型不匹配在Boost.Interprocess中共享内存映射 [英] want to efficiently overcome mismatch between key types in a map in Boost.Interprocess shared memory

查看:456
本文介绍了要有效地克服密钥类型不匹配在Boost.Interprocess中共享内存映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在共享内存中使用Boost.Interprocess中创建一个映射(从串来串在这个例子中)。
编译器似乎想逼我,检索过程中从地图上看,在分配内存
管理的段刚(不必要的)包含查询词。

I'm creating a map (from string to string in this example) in shared memory using Boost.Interprocess. The compiler seems to want to force me, during retrieval from the map, to allocate memory in the managed segment just to (unnecessarily) contain the query term.

我想能
查找值在一个共享的地图更加有效,通过匹配地图的针对已经在非共享内存实例键,不执行此额外分配。但它的
拒绝编译如果我尝试使用的std :: string的为const char * 作为参数传递给地图的找到方法。
(见底部编译器错误消息)。

I'd like to be able to look up values in a shared map more efficiently, by matching the map's keys against instances that are already in non-shared memory, without performing this extra allocation. But it's refusing to compile if I try to use a std::string or const char * as the argument to the map's find method. (see compiler error messages at bottom).

我是否需要界定某种
我的共享内存键类型及其非共享当量(的std ::字符串在这个例子中)之间的比较方法是什么?如果是的话,又该
这个模样,我应该如何使地图使用它呢?如果不是这样,我该怎么办?

Do I need to define some sort of comparator method between my shared-memory key type and its non-shared equivalent (std::string in this example)? If so, what should this look like and how should I make the map use it? If not, what should I do?

这里的code,其次是编译器错误。问题是对底部的main()

Here's the code, followed by the compiler errors. The problem is towards the bottom of main().

// shmap2.cpp

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>

//Typedefs of allocators and containers
namespace Shared
{
    typedef boost::interprocess::managed_shared_memory
        Segment;

    typedef boost::interprocess::managed_shared_memory::segment_manager
        SegmentManager;

    typedef boost::interprocess::allocator< void, SegmentManager >
        Allocator;

    typedef boost::interprocess::allocator< char, SegmentManager >
        CharAllocator;

    typedef boost::interprocess::basic_string< char, std::char_traits< char >, CharAllocator > 
        String;

    typedef std::less< String >
        StringComparator;

    // Definition of the shared map from String to String
    // (To avoid confusion, let's strictly use Python-like definitions of "key", "value" and "item")
    typedef std::pair< const String, String >
        MapItem;

    typedef boost::interprocess::allocator< MapItem, SegmentManager >
        MapItemAllocator;

    typedef boost::interprocess::map< String, String, StringComparator, MapItemAllocator >
        Map;
}

int main( void )
{
    struct shm_remove
    {
        shm_remove() { boost::interprocess::shared_memory_object::remove( "MySharedMemory" ); }
        ~shm_remove(){ boost::interprocess::shared_memory_object::remove( "MySharedMemory" ); }
    } remover;

    // Create shared memory
    Shared::Segment seg( boost::interprocess::create_only, "MySharedMemory", 65536 );

    // An allocator instance that can be converted to any allocator< T, Shared::SegmentManager > type
    Shared::Allocator alloc( seg.get_segment_manager() );

    // An instance of the string comparator, to construct the map
    Shared::StringComparator cmp;

    // Construct the shared memory map
    Shared::Map * myMapPtr = seg.construct< Shared::Map >( "myMap" )( cmp, alloc );

    // Here's the problem:

    // std::string key( "foo" );            // Compilation fails if you use this.
    // char key[] = "foo";                  // Compilation fails if you use this.
    Shared::String key( "foo", alloc );     // This the only version I can get to work.
                                            // But it forces you to create a copy of
                                            // the key you are searching for, in
                                            // the managed segment.

    // This is the point of the exercise:
    Shared::Map::iterator it = myMapPtr->find( key );

    return 0;
}

随着的std ::字符串

$ g++ -o shmap2 -D BOOST_ALL_NO_LIB  -I ../boost_1_57_0  shmap2.cpp
shmap2.cpp:79:40: error: no matching member function for call to 'find'
                Shared::Map::iterator it = myMapPtr->find( key );
                                           ~~~~~~~~~~^~~~
../boost_1_57_0/boost/container/detail/tree.hpp:1089:13: note: candidate function not
      viable: no known conversion from 'std::string' (aka 'basic_string<char,
      char_traits<char>, allocator<char> >') to 'const key_type' (aka 'const
      boost::container::basic_string<char, std::__1::char_traits<char>,
      boost::interprocess::allocator<char, boost::interprocess::segment_manager<char,
      boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
      boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >
      >') for 1st argument
   iterator find(const key_type& k)
            ^
../boost_1_57_0/boost/container/detail/tree.hpp:1092:19: note: candidate function not
      viable: no known conversion from 'std::string' (aka 'basic_string<char,
      char_traits<char>, allocator<char> >') to 'const key_type' (aka 'const
      boost::container::basic_string<char, std::__1::char_traits<char>,
      boost::interprocess::allocator<char, boost::interprocess::segment_manager<char,
      boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
      boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >
      >') for 1st argument
   const_iterator find(const key_type& k) const
                  ^
1 error generated.

使用为const char *

$ g++ -o shmap2 -D BOOST_ALL_NO_LIB  -I ../boost_1_57_0  shmap2.cpp
In file included from shmap2.cpp:17:
In file included from ../boost_1_57_0/boost/interprocess/containers/string.hpp:19:
../boost_1_57_0/boost/container/string.hpp:676:59: error: no matching constructor for
      initialization of 'allocator_type' (aka 'boost::interprocess::allocator<char,
      boost::interprocess::segment_manager<char,
      boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
      boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> >')
   basic_string(const CharT* s, const allocator_type& a = allocator_type())
                                                          ^
shmap2.cpp:79:46: note: in instantiation of default function argument expression for
      'basic_string<char, std::__1::char_traits<char>, boost::interprocess::allocator<char,
      boost::interprocess::segment_manager<char,
      boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,
      boost::interprocess::offset_ptr<void, long, unsigned long, 0>, 0>, iset_index> > >'
      required here
                Shared::Map::iterator it = myMapPtr->find( key );
                                                           ^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:140:4: note: candidate
      constructor template not viable: requires single argument 'other', but no
      arguments were provided
   allocator(const allocator<T2, SegmentManager> &other)
   ^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:129:4: note: candidate
     constructor not viable: requires single argument 'segment_mngr', but no arguments
     were provided
   allocator(segment_manager *segment_mngr)
   ^
../boost_1_57_0/boost/interprocess/allocators/allocator.hpp:134:4: note: candidate
     constructor not viable: requires single argument 'other', but no arguments were
     provided
   allocator(const allocator &other)
   ^
1 error generated.

更新: sehe的建议下,下面,我试图取代

UPDATE: following the suggestion of sehe, below, I tried replacing

typedef std::less< String >
    StringComparator;

typedef struct
{
    template< typename T, typename U >
    bool operator()( const T & t, const U & u )
        const { return t < u; }
} StringComparator;

但得到相同的两个编译器错误。

but got the same two compiler errors.

推荐答案

您可以使用自定义比较

   struct MyLess {
        template <typename T, typename U>
            bool operator()(const T&t, const U&u) const
        {
            return t<u;
        }
    };

在您的code你可以的typedef为 StringComparator

In your code you can just typedef it as StringComparator

更新以注释

如果您希望用升压更换的std ::地图 / 的boost ::容器::地图多指数容器(它支持查找 CompatibleKey ),下面是如何做到这一点的演示:

If you want to replace the std::map/boost::container::map with a Boost Multi Index container (which supports lookup by CompatibleKey), here's a demo of how to do it:

我已经借了一些想法的从文档部分的 Emulating标准集装箱与的multi_index_container

I've borrowed some of the idea's from the documentation section Emulating standard containers with multi_index_container.

注意的std ::字符串作为查找键仍然无法工作,但你可以很容易地使用 .c_strio()在该事件。

Note that std::string as the lookup key still won't work, but you can easily use .c_strio() in that event.

<大骨节病> 住在Coliru

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>

namespace emulation {
    template <typename T1,typename T2,typename Alloc>
        struct mutable_pair
        {
            typedef T1 first_type;
            typedef T2 second_type;

            mutable_pair(Alloc alloc):first(T1(alloc)),second(T2(alloc)){}
            mutable_pair(const T1& f,const T2& s):first(f),second(s){}
            mutable_pair(const std::pair<T1,T2>& p):first(p.first),second(p.second){}

            T1         first;
            mutable T2 second;
        };

    using namespace boost::multi_index;

    template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
        using map = multi_index_container<
            Element,
            indexed_by<
                ordered_unique<member<Element,Key,&Element::first>,Compare>
            >,
            typename Allocator::template rebind<Element>::other
        >;

  template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
    using multimap = multi_index_container<
        Element,
        indexed_by<
            ordered_non_unique<member<Element,Key,&Element::first>,Compare>
        >,
        typename Allocator::template rebind<Element>::other
    >;

  template <typename Key, typename T, typename Compare, typename Allocator> 
      struct wrap_map : map<Key, T, Compare, Allocator> {
          typedef map<Key, T, Compare, Allocator> base_type;
          typedef typename base_type::template nth_index<0>::type index_type;

          wrap_map(Allocator alloc) : base_type({}, alloc)
          {
          }

          wrap_map(Compare cmp, Allocator alloc) : base_type(
                  typename base_type::ctor_args_list{
                    typename index_type::ctor_args { typename index_type::key_from_value {}, cmp }
                  },
                  alloc)
          {
          }
      };
}

// Typedefs of allocators and containers
namespace Shared {
    typedef boost::interprocess::managed_shared_memory Segment;
    typedef boost::interprocess::managed_shared_memory::segment_manager SegmentManager;
    typedef boost::interprocess::allocator<void, SegmentManager> Allocator;
    typedef boost::interprocess::allocator<char, SegmentManager> CharAllocator;
    typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> String;

    struct MyLess {
        template <typename T, typename U> bool operator()(const T &t, const U &u) const { return t < u; }
    };
    typedef MyLess StringComparator;


    typedef boost::interprocess::allocator<char, SegmentManager> StringAlloc;
    typedef emulation::mutable_pair<const String, String, StringAlloc> MapItem;
    typedef boost::interprocess::allocator<MapItem, SegmentManager> MapItemAllocator;
    typedef emulation::wrap_map<String, String, StringComparator, MapItemAllocator> Map;
}

int main(void) {
    struct shm_remove {
        shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
        ~shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
    } remover;

    // Create shared memory
    Shared::Segment seg(boost::interprocess::create_only, "MySharedMemory", 65536);
    Shared::Allocator alloc(seg.get_segment_manager());

    // An instance of the string comparator, to construct the map
    Shared::StringComparator cmp;

    // Construct the shared memory map
    Shared::Map *myMapPtr = seg.construct<Shared::Map>("myMap")(cmp, alloc);

    myMapPtr->emplace(Shared::String("foo", alloc), Shared::String("bar", alloc));
    myMapPtr->emplace(Shared::String("goo", alloc), Shared::String("car", alloc));
    myMapPtr->emplace(Shared::String("hoo", alloc), Shared::String("dar", alloc));

    Shared::String key("foo", alloc);

    // This is the point of the exercise:
    auto it = myMapPtr->find(key);

    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    // this is now okay too
    char szkey[] = "foo";
    it = myMapPtr->find(szkey);
    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    // this is now okay too
    std::string skey("foo");
    it = myMapPtr->find(skey.c_str());
    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    return 0;
}

打印:

Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'


作用域分配器额外Awesomesauce?

现在,有趣的是,提升容器支持作用域分配器,所以你可以做客场与分配器的反复传球,但是,Boost多指数可悲的是不支持它的完全的。这里有一个中间的办法,是关于据我可以得到它(还有些用户友好的):


Scoped Allocators For Extra Awesomesauce?

Now, interestingly, Boost Container supports Scoped Allocators, so you could do away with the repeated passing of the allocators, however, Boost Multi Index sadly doesn't support it fully. Here's a halfway approach that's about as far as I could get it (still somewhat user friendlier):

<大骨节病> 住在Coliru

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>

#include <boost/container/scoped_allocator.hpp>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>

namespace emulation {
    template <typename T1,typename T2,typename Alloc>
        struct mutable_pair
        {
            typedef Alloc allocator_type;
            typedef T1 first_type;
            typedef T2 second_type;

            mutable_pair(Alloc alloc):first(T1(alloc)),second(T2(alloc)){}
            mutable_pair(const T1& f,const T2& s):first(f),second(s){}
            mutable_pair(const std::pair<T1,T2>& p):first(p.first),second(p.second){}

            template <typename U, typename V, typename Alloc2>
            mutable_pair(const U& f,const V& s, Alloc2 alloc):first(f, alloc),second(s, alloc){}

            T1         first;
            mutable T2 second;
        };

    using namespace boost::multi_index;

    template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
        using map = multi_index_container<
            Element,
            indexed_by<
                ordered_unique<member<Element,Key,&Element::first>,Compare>
            >,
            typename Allocator::template rebind<Element>::other
        >;

  template <typename Key, typename T, typename Compare, typename Allocator, typename Element = mutable_pair<Key, T, Allocator> >
    using multimap = multi_index_container<
        Element,
        indexed_by<
            ordered_non_unique<member<Element,Key,&Element::first>,Compare>
        >,
        typename Allocator::template rebind<Element>::other
    >;

  template <typename Key, typename T, typename Compare, typename Allocator> 
      struct wrap_map : map<Key, T, Compare, Allocator> {
          typedef map<Key, T, Compare, Allocator> base_type;
          typedef typename base_type::template nth_index<0>::type index_type;

          wrap_map(Allocator alloc) : base_type({}, alloc)
          { 
          }

          wrap_map(Compare cmp, Allocator alloc) : base_type(
                  typename base_type::ctor_args_list{
                    typename index_type::ctor_args { typename index_type::key_from_value {}, cmp }
                  },
                  alloc)
          { 
          }
      };
}


// Typedefs of allocators and containers
namespace Shared {
    typedef boost::interprocess::managed_shared_memory Segment;
    typedef Segment::segment_manager SegmentManager;
    typedef boost::container::scoped_allocator_adaptor<boost::interprocess::allocator<void, SegmentManager> > Allocator;

    typedef Allocator::rebind<char>::other CharAllocator;
    typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> String;

    struct MyLess {
        template <typename T, typename U> bool operator()(const T &t, const U &u) const { return t < u; }
    };
    typedef MyLess StringComparator;

    typedef emulation::mutable_pair<String, String, CharAllocator> MapItem;
    typedef Allocator::rebind<MapItem>::other MapItemAllocator;
    typedef emulation::wrap_map<String, String, StringComparator, MapItemAllocator> Map;
}

int main(void) {
    struct shm_remove {
        shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
        ~shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
    } remover;

    // Create shared memory
    Shared::Segment seg(boost::interprocess::create_only, "MySharedMemory", 65536);
    Shared::Allocator alloc(seg.get_segment_manager());

    // An instance of the string comparator, to construct the map
    Shared::StringComparator cmp;

    // Construct the shared memory map
    Shared::Map *myMapPtr = seg.construct<Shared::Map>("myMap")(cmp, alloc);

    myMapPtr->emplace("foo", "bar", alloc);
    myMapPtr->emplace("goo", "car", alloc);
    myMapPtr->emplace("hoo", "dar", alloc);

    // This the only version I can get to work.  But it forces you to create a
    // copy of the key you are searching for, in the managed segment.
    Shared::String key("foo", alloc);     

    // This is the point of the exercise:
    auto it = myMapPtr->find(key);

    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    // this is now okay too
    char szkey[] = "foo";
    it = myMapPtr->find(szkey);
    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    // this is now okay too
    std::string skey("foo");
    it = myMapPtr->find(skey.c_str());
    if (it!=myMapPtr->end())
        std::cout << "Found: '" << it->first << "' -> '" << it->second << "'\n";

    return 0;
}

另外打印

Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'
Found: 'foo' -> 'bar'

这篇关于要有效地克服密钥类型不匹配在Boost.Interprocess中共享内存映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆