c++ - 想要有效地克服 Boost.Interprocess 共享内存中映射中关键类型之间的不匹配

标签 c++ boost shared-memory

我正在使用 Boost.Interprocess 在共享内存中创建一个映射(在本示例中从字符串到字符串)。 编译器似乎想强制我在从映射检索期间在 托管段只是为了(不必要地)包含查询项。

我希望能够 通过将映射的键与非共享内存中已有的实例进行匹配,可以更有效地查找共享映射中的值,而无需执行此额外的分配。但它是 如果我尝试使用 std::stringconst char * 作为 map 的 find 方法的参数,则拒绝编译。 (请参阅底部的编译器错误消息)。

我需要定义某种 我的共享内存 key 类型与其非共享等效 key 类型之间的比较器方法(本例中为 std::string )?如果是这样,应该怎样做 这看起来像什么,我应该如何让 map 使用它?如果没有,我该怎么办?

这是代码,后面是编译器错误。问题出在 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::string 作为:

$ 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的建议,下面,我尝试替换

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;

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

最佳答案

您可以使用自定义比较器

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

在您的代码中,您只需将其键入为 StringComparator

更新到评论


多索引来救援

如果您想将 std::map/boost::container::map 替换为 Boost Multi Index 容器(支持通过 CompatibleKey 查找) ),这里是如何做到这一点的演示:

我从文档部分借用了一些想法 Emulating standard containers with multi_index_container

请注意,std::string 作为查找键仍然不起作用,但您可以在该事件中轻松使用 .c_strio()

Live On 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 Container 支持作用域分配器,因此您可以消除分配器的重复传递,但是遗憾的是,Boost Multi Index 并不完全支持它。这是我所能得到的一种折中方法(仍然对用户更友好):

Live On 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'

关于c++ - 想要有效地克服 Boost.Interprocess 共享内存中映射中关键类型之间的不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27328835/

相关文章:

linux - 从 C++ 应用程序代码调用 Linux 系统调用?

c++ - 在 Torch C++ API 中,如何快速写入张量的内部数据?

c++ - 为什么 pthread_mutex_t 在尝试通过来自两个不同进程的共享内存进行锁定时会出现段错误?

c++ - 将 Vector 拆分为 block - 奇怪的结果

c++ - boost spirit : Why does phrase_parse behave differently to parse when parsing eol?

c++ - boost asio - 检查是否有任何内容可以从串行端口读取

c++ - Boost 编译点云库时出现的问题

c++ - 我们如何准备小型内存池,其中每个线程都可以独立访问一定范围的位置?

c++ - Linux通过pid获取窗口图标

c++ - Firebird C 客户端 API : statement, 事务和游标生命周期