Boost 分配器的向量大小不正确
Incorrect vector size with Boost allocators
以下程序在内存映射文件的 space 中为 c
类型的对象 C
分配内存。将单个字符添加到包含在 c
中的矢量会将矢量的报告大小从 0 更改为 18446744073709551520。
#include <iostream>
#include <new>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
using namespace boost::interprocess;
class C;
typedef managed_mapped_file::segment_manager SegmentManager;
typedef allocator<void, SegmentManager> VoidAllocator;
typedef allocator<char, SegmentManager> CharAllocator;
typedef allocator<C, SegmentManager> CAllocator;
typedef offset_ptr<C> CPtr;
class C {
public:
std::vector<char, CharAllocator> data;
C(const VoidAllocator &voidAlloc) : data(voidAlloc) {}
void add_char() {
std::cout << data.size() << std::endl;
data.push_back('x');
std::cout << data.size() << std::endl;
}
};
int main(int argc, char *argv[]) {
boost::filesystem::remove_all("file");
managed_mapped_file segment(create_only, "file", 100000);
VoidAllocator allocator_instance(segment.get_segment_manager());
CAllocator alloc_c(allocator_instance);
CPtr c = alloc_c.allocate_one();
*c = C(allocator_instance);
c->add_char();
return 0;
}
当 c
分配在堆栈上而不是动态分配时,不会出现此问题。
C c(allocator_instance);
c.add_char();
我使用以下命令使用 Boost 1.62 和 g++ 6.3.0-18 在 Debian GNU/Linux stretch 上编译代码。
g++ -Wall -pthread -lboost_system -lboost_filesystem t.cpp -o t
似乎将构造的对象从默认内存池移动到段 1 以某种方式混淆了向量的实现。使用construct
方法直接在segment内存池内构造对象即可解决
CPtr c = segment.construct<C>(anonymous_instance) (allocator_instance);
分配器returns原始的、未初始化的内存。
通过它间接指向类型 C
的对象是 Undefined Behaviour.
当然,您可以使用 placement-new 实际完成繁重的工作:
CPtr c = alloc_c.allocate_one();
new (&*c) C(allocator_instance);
请注意,同样,对于非 POD(或者实际上,不可平凡破坏的类型),您还必须记住在适当的时间调用析构函数:
CPtr c = alloc_c.allocate_one();
new (&*c) C(allocator_instance);
*c = C(allocator_instance);
c->add_char();
c->~C();
alloc_c.deallocate_one(c);
但是正如您已经指出的那样,高级方法避免了 new/delete 并使用了段管理器:
CPtr c = segment.construct<C>("Name") (allocator_instance);
演示
正在使用
find_or_construct
这样可以按名称检索共享对象(如果您不想要,请使用 anonymous
或 unique
实例;另请注意,您可以通过相同的名称实例化多个实例)
使用 allocator_type
有助于使用作用域分配器适配器(思考:vector<C>
)
参数化C
使得它可以很容易地与标准分配器和共享内存分配器一起使用
使用段管理器指针和分配器实例的隐式转换
隐藏实现细节offset_ptr
(90% 的时间你不需要知道)
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <iostream>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_mapped_file;
using Manager = Segment::segment_manager;
template <typename T = void>
using Alloc = bip::allocator<T, Manager>;
template <typename T>
using Vector = bip::vector<T, Alloc<T> >;
template <typename Alloc = std::allocator<void> >
struct C {
using allocator_type = Alloc;
bip::vector<char, typename Alloc::template rebind<char>::other> data;
C(Alloc alloc = {}) : data(alloc) {}
void add_char() {
std::cout << data.size() << std::endl;
data.push_back('x');
std::cout << data.size() << std::endl;
}
};
}
int main() {
std::remove("file");
Shared::Segment mmf(bip::create_only, "file", 1000000);
using Alloc = Shared::Alloc<>;
using C = Shared::C<Alloc>;
auto* c = mmf.find_or_construct<C>("byname")(mmf.get_segment_manager());
c->add_char();
//mmf.destroy_ptr(c);
}
版画
0
1
以下程序在内存映射文件的 space 中为 c
类型的对象 C
分配内存。将单个字符添加到包含在 c
中的矢量会将矢量的报告大小从 0 更改为 18446744073709551520。
#include <iostream>
#include <new>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
using namespace boost::interprocess;
class C;
typedef managed_mapped_file::segment_manager SegmentManager;
typedef allocator<void, SegmentManager> VoidAllocator;
typedef allocator<char, SegmentManager> CharAllocator;
typedef allocator<C, SegmentManager> CAllocator;
typedef offset_ptr<C> CPtr;
class C {
public:
std::vector<char, CharAllocator> data;
C(const VoidAllocator &voidAlloc) : data(voidAlloc) {}
void add_char() {
std::cout << data.size() << std::endl;
data.push_back('x');
std::cout << data.size() << std::endl;
}
};
int main(int argc, char *argv[]) {
boost::filesystem::remove_all("file");
managed_mapped_file segment(create_only, "file", 100000);
VoidAllocator allocator_instance(segment.get_segment_manager());
CAllocator alloc_c(allocator_instance);
CPtr c = alloc_c.allocate_one();
*c = C(allocator_instance);
c->add_char();
return 0;
}
当 c
分配在堆栈上而不是动态分配时,不会出现此问题。
C c(allocator_instance);
c.add_char();
我使用以下命令使用 Boost 1.62 和 g++ 6.3.0-18 在 Debian GNU/Linux stretch 上编译代码。
g++ -Wall -pthread -lboost_system -lboost_filesystem t.cpp -o t
似乎将构造的对象从默认内存池移动到段 1 以某种方式混淆了向量的实现。使用construct
方法直接在segment内存池内构造对象即可解决
CPtr c = segment.construct<C>(anonymous_instance) (allocator_instance);
分配器returns原始的、未初始化的内存。
通过它间接指向类型 C
的对象是 Undefined Behaviour.
当然,您可以使用 placement-new 实际完成繁重的工作:
CPtr c = alloc_c.allocate_one();
new (&*c) C(allocator_instance);
请注意,同样,对于非 POD(或者实际上,不可平凡破坏的类型),您还必须记住在适当的时间调用析构函数:
CPtr c = alloc_c.allocate_one();
new (&*c) C(allocator_instance);
*c = C(allocator_instance);
c->add_char();
c->~C();
alloc_c.deallocate_one(c);
但是正如您已经指出的那样,高级方法避免了 new/delete 并使用了段管理器:
CPtr c = segment.construct<C>("Name") (allocator_instance);
演示
正在使用
find_or_construct
这样可以按名称检索共享对象(如果您不想要,请使用anonymous
或unique
实例;另请注意,您可以通过相同的名称实例化多个实例)使用
allocator_type
有助于使用作用域分配器适配器(思考:vector<C>
)参数化
C
使得它可以很容易地与标准分配器和共享内存分配器一起使用使用段管理器指针和分配器实例的隐式转换
隐藏实现细节
offset_ptr
(90% 的时间你不需要知道)
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <iostream>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_mapped_file;
using Manager = Segment::segment_manager;
template <typename T = void>
using Alloc = bip::allocator<T, Manager>;
template <typename T>
using Vector = bip::vector<T, Alloc<T> >;
template <typename Alloc = std::allocator<void> >
struct C {
using allocator_type = Alloc;
bip::vector<char, typename Alloc::template rebind<char>::other> data;
C(Alloc alloc = {}) : data(alloc) {}
void add_char() {
std::cout << data.size() << std::endl;
data.push_back('x');
std::cout << data.size() << std::endl;
}
};
}
int main() {
std::remove("file");
Shared::Segment mmf(bip::create_only, "file", 1000000);
using Alloc = Shared::Alloc<>;
using C = Shared::C<Alloc>;
auto* c = mmf.find_or_construct<C>("byname")(mmf.get_segment_manager());
c->add_char();
//mmf.destroy_ptr(c);
}
版画
0
1