代码之家  ›  专栏  ›  技术社区  ›  Dusko Murtovski

将std::vector复制到boost::进程间::vector

  •  1
  • Dusko Murtovski  · 技术社区  · 7 年前

    我想使用boost interprocess共享对象的向量。对象来自以下结构:

    struct Foo
        {
            int id;
            float time;
            bool isFoo;
    
            float myArray[7];
    
            std::vector<int> vectorData;
        };
    

    我正在创建boost进程间分配器和进程间向量:

    typedef allocator<Foo, managed_shared_memory::segment_manager>  FooAllocator;
    
    typedef std::vector<Foo, FooAllocator> FooVector;
    

    在我的主要函数中,我根据以下内容初始化内存段、分配器和向量:

    boost -> creating vectors in shared memory

    因此:

    managed_shared_memory mem_segment(open_or_create, "MemShare", 65536);
    const FooAllocator alloc_inst(mem_segment.get_segment_manager());
    
    fooVector = mem_segment.find_or_construct<FooVector>("FooVector")(alloc_inst);
    

    现在,这适用于Foo结构中除vector之外的所有数据类型。因此,如果我尝试共享它,我会从Foo获得所有成员,对于向量数据,我会得到“未定义的内存位置” 我知道std::vector不能直接共享。所以我用boost::进程间:vector创建了新的Foo结构

    struct FooInter
        {
            int id;
            float time;
            bool isFoo;
    
            float myArray[7];
            MyVector* pointcloud;
        };
    

    其中MyVector为:

    typedef allocator<int, managed_shared_memory::segment_manager> VectorAllocator;
    typedef boost::interprocess::vector<int, VectorAllocator> MyVector;
    

    我正在为MyVector分配内存,

    const VectorAllocator vec_alloc_inst(mem_segment.get_segment_manager());
    MyVector* tmpVec = mem_segment.construct<MyVector>("MyVector")(vec_alloc_inst);
    

    那么我现在要做的就是把Foo映射到FooInter。我正在映射for循环中的向量数据:

        for (int t = 0; t < foo.vectorData.size()-1; t++) {
            tmpVec->push_back(foo.vectorData[t]);
        }
    

    然后将tmpVec复制到fooInter中。矢量数据:

    memcpy(fooInter.pointcloud, tmpVec, sizeof(int) * tmpVec->size());
    

    这对foo的整个尺寸都有效,但不适用。矢量数据。所以它适用于100个项目,但如果我选择foo。矢量数据。size()返回错误的内存分配。

    谁能帮我一下吗。我需要知道共享这种结构的正确方式。我觉得我所做的是完全错误的。也许我需要将向量序列化为字符串或类似的内容。

    编辑:

    根据sehe的回答:

    我有来自类型的对象消息:

    struct Foo
        {
            int id;
            float time;
            bool isFoo;
    
            float myArray[7];
    
            std::vector<int> pointcloud;
        };
    

    我需要在inter\u foos中传递该对象。所以在sehe的代码中:

    int main() {
        auto segment = Shared::open();
        auto& inter_foos = *segment.find_or_construct<InterFoos>("InterFoos")(segment.get_segment_manager());
    
        // you can directly append to the shared memory vector
        int nextid = inter_foos.size();
        //instead of this
        inter_foos.push_back({++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, Ints ({10,20,30}, segment.get_segment_manager()) });
        //i need this
            inter_foos.push_back({msg.id, msg.time, true, msg.myArray, Ints (msg.pointcloud, segment.get_segment_manager()) });
    
        //i can't pass msg.poincloud to this object!!!
    
        // or copy from a non-shared vector:
        std::vector<Foo> const local {
            {++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, {10,20,30} },
            {++nextid, 1, true, {.2,.3,.4,.5,.6,.7,.8}, {20,30,40} },
            {++nextid, 2, true, {.3,.4,.5,.6,.7,.8,.9}, {30,40,50} },
        };
    
        for (auto& local_foo : local)
            inter_foos.emplace_back(local_foo);
    
        // print the current contents
        for (auto& foo : inter_foos)
            std::cout << foo << "\n"; 
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   sehe    7 年前

    您可以使用以下方法

    查看此演示

    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>
    
    #include <iostream>
    #include <vector>
    
    namespace Shared {
        namespace bip = boost::interprocess;
        namespace bc  = boost::container;
    
        using Segment                     = bip::managed_shared_memory;
        using Manager                     = Segment::segment_manager;
        template <typename T> using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Manager> >;
        template <typename T> using Vector= bip::vector<T, Alloc<T> >;
    
        Segment open() { return { bip::open_or_create, "MySharedMemory", 10ul<<20 }; }
    
        template <typename Alloc = Alloc<void> >
        struct Foo {
            using allocator_type = typename Alloc::template rebind<Foo>::other;
            using Ints = bip::vector<int, typename Alloc::template rebind<int>::other>;
    
            Foo(int id, float time, bool isFoo = false, std::initializer_list<float> floats = {}, Ints data = {})
                : id(id), time(time), isFoo(isFoo), vectorData(std::move(data))
            {
                std::copy_n(floats.begin(), std::min(floats.size(), 7ul), myArray);
            }
    
            template <typename OA, typename A>
            Foo(Foo<OA> const& other, A alloc = {}) 
                : id(other.id), time(other.time), isFoo(other.isFoo),
                  vectorData(other.vectorData.begin(), other.vectorData.end(), alloc)
            {
                std::copy(std::begin(other.myArray), std::end(other.myArray), myArray);
            }
    
            int   id;
            float time;
            bool  isFoo;
            float myArray[7] = {};
            Ints  vectorData;
        };
    
        template <typename A>
        std::ostream& operator<<(std::ostream& os, Foo<A> const& f) {
            os << "{" 
               << f.id << ", "
               << std::fixed << f.time << ", "
               << std::boolalpha << f.isFoo << ", "
               << "[";
    
            std::copy(std::begin(f.myArray), std::end(f.myArray), std::ostream_iterator<float>(std::cout, ";"));
            os << "], [";
            std::copy(std::begin(f.vectorData), std::end(f.vectorData), std::ostream_iterator<int>(std::cout, ";"));
            return os << "] }";
        }
    
    }
    
    using Foo       = Shared::Foo<std::allocator<void> >;
    using InterFoo  = Shared::Foo<>;
    
    using InterFoos = Shared::Vector<InterFoo>;
    using Ints      = Shared::Vector<int>;
    
    int main() {
        auto segment = Shared::open();
        auto& inter_foos = *segment.find_or_construct<InterFoos>("InterFoos")(segment.get_segment_manager());
    
        // you can directly append to the shared memory vector
        int nextid = inter_foos.size();
        inter_foos.push_back({++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, Ints ({10,20,30}, segment.get_segment_manager()) });
    
        // or copy from a non-shared vector:
        std::vector<Foo> const local {
            {++nextid, 0, true, {.1,.2,.3,.4,.5,.6,.7}, {10,20,30} },
            {++nextid, 1, true, {.2,.3,.4,.5,.6,.7,.8}, {20,30,40} },
            {++nextid, 2, true, {.3,.4,.5,.6,.7,.8,.9}, {30,40,50} },
        };
    
        for (auto& local_foo : local)
            inter_foos.emplace_back(local_foo);
    
        // print the current contents
        for (auto& foo : inter_foos)
            std::cout << foo << "\n"; 
    }
    

    打印:

    {1, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {2, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {3, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
    {4, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }
    

    第二次运行:

    {1, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {2, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {3, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
    {4, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }
    {5, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {6, 0.000000, true, [0.100000;0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;], [10;20;30;] }
    {7, 1.000000, true, [0.200000;0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;], [20;30;40;] }
    {8, 2.000000, true, [0.300000;0.400000;0.500000;0.600000;0.700000;0.800000;0.900000;], [30;40;50;] }
    

    作用域分配器

    请注意:

        for (auto& local_foo : local)
            inter_foos.emplace_back(local_foo);
    

    之所以有效,是因为Boost的容器实现支持并传递作用域分配器。如果你没有使用它,事情会是这样的: Coliru现场直播

    template <typename T> using Alloc = bip::allocator<T, Manager>;
    // ...
    
    for (auto& local_foo : local)
        inter_foos.emplace_back(local_foo, segment.get_segment_manager());
    

    使用映射文件,因为COLIRU上不支持共享内存

        2
  •  1
  •   Martin Bonner supports Monica    7 年前

    我无法想象使用 memcpy 复制 MyVector 将会很好地工作。当然,您需要的是:

    void FooInter::setVector(const std::vector<int>& vec) {
        const VectorAllocator vec_alloc_inst(mem_segment.get_segment_manager());
        const auto tmp = mem_segment.construct<MyVector>("MyVector")(vec_alloc_inst);
        tmp->insert(tmp->begin(), vec.begin(), vec.end());
        pointcloud = tmp;
    }
    

    换句话说,构建pointcloud指向的对象,然后插入其中。