将 std::vector 复制到 boost::interprocess::vector
Copy std::vector to boost::interprocess::vector
我想使用 boost 进程间共享对象向量。对象来自以下结构:
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 结构中的所有数据类型。因此,如果我尝试分享这个,我会从 Foo 获得所有成员,而对于矢量数据,我会得到 "Undefined memory location"
我知道 std::vector 不能直接分享。所以我用 boost::interprocess: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.vectorData:
memcpy(fooInter.pointcloud, tmpVec, sizeof(int) * tmpVec->size());
这有效,但不适用于 foo.vectorData 的整个大小。所以它适用于 100 个项目,但是如果我使用 foo.vectorData.size() 它 returns 错误的内存分配。
有人可以帮我解决这个问题吗?我需要知道共享此类结构的正确方法。我觉得我所做的是完全错误的。也许我需要将向量序列化为字符串或类似的东西。
编辑:
根据sehe的回答:
我有来自以下类型的对象消息:
struct Foo
{
int id;
float time;
bool isFoo;
float myArray[7];
std::vector<int> pointcloud;
};
我需要在 inter_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";
}
我无法想象使用 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指向的对象,然后插入进去
您可以使用
中的方法
- making non-shared copies of boost::interprocess shared memory objects
查看此演示¹
#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 的容器实现支持并传递了作用域分配器。如果你不使用它,事情会是这样的:Live On 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
不支持共享内存
我想使用 boost 进程间共享对象向量。对象来自以下结构:
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 结构中的所有数据类型。因此,如果我尝试分享这个,我会从 Foo 获得所有成员,而对于矢量数据,我会得到 "Undefined memory location" 我知道 std::vector 不能直接分享。所以我用 boost::interprocess: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.vectorData:
memcpy(fooInter.pointcloud, tmpVec, sizeof(int) * tmpVec->size());
这有效,但不适用于 foo.vectorData 的整个大小。所以它适用于 100 个项目,但是如果我使用 foo.vectorData.size() 它 returns 错误的内存分配。
有人可以帮我解决这个问题吗?我需要知道共享此类结构的正确方法。我觉得我所做的是完全错误的。也许我需要将向量序列化为字符串或类似的东西。
编辑:
根据sehe的回答:
我有来自以下类型的对象消息:
struct Foo
{
int id;
float time;
bool isFoo;
float myArray[7];
std::vector<int> pointcloud;
};
我需要在 inter_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";
}
我无法想象使用 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指向的对象,然后插入进去
您可以使用
中的方法- making non-shared copies of boost::interprocess shared memory objects
查看此演示¹
#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 的容器实现支持并传递了作用域分配器。如果你不使用它,事情会是这样的:Live On 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
不支持共享内存