Boost分配器的向量大小不正确

时间:2018-01-10 06:41:09

标签: c++ vector boost allocator

以下程序在内存映射文件的空间内为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上编译代码。

g++ -Wall -pthread  -lboost_system -lboost_filesystem t.cpp -o t

2 个答案:

答案 0 :(得分:1)

似乎将构造的对象从默认内存池移动到段1会以某种方式混淆向量的实现。使用construct方法直接在段内存池中构造对象可以解决问题。

CPtr c = segment.construct<C>(anonymous_instance) (allocator_instance);

答案 1 :(得分:1)

分配器返回未初始化的原始内存。

通过它指向类似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);

但正如您已经指出的那样,高级方法避免了新的/删除并使用了段管理器:

CPtr c = segment.construct<C>("Name") (allocator_instance); 

样本

使用

  • find_or_construct因此可以按名称检索共享对象(如果您不想要,请使用anonymousunique实例;另请注意,您可以通过实例化实例化多个实例同名)

  • 使用allocator_type有助于使用作用域分配器适配器(想想:vector<C>

  • 参数化C可以很容易地将它与标准分配器和共享内存分配器一起使用

  • 使用段管理器指针和分配器实例的隐式转换

  • 隐藏实施细节offset_ptr(有90%的时间您不需要了解)

Live On Coliru

#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