【问题标题】:Dynamic vector of contiguously allocated objects in the Heap堆中连续分配对象的动态向量
【发布时间】:2021-07-08 06:16:08
【问题描述】:

我正在尝试构建一个类来管理 std::vector 指向必须在堆中连续分配的对象的指针。

我遇到的问题是构建如下图的向量会导致非连续分配的对象:

std::vector<T*> objects{};
for (size_t i = 0; i < n; i++) objects.push_back(new T());

这是因为new T() 的两次连续执行不必在内存中产生连续的对象。所以解决方案是改用new[] 运算符,这让我接受了这个实现:

template<class T>
class HeapVector
{
private:
  std::vector<T*> elems_{};
  const size_t BUFFER_SIZE_{}; // Buffer size
  size_t idx_{}; // Index controlling the index local to the buffer.
  T * buffer_ = nullptr; // Buffer

public:
  HeapVector() = default;
  HeapVector(const size_t BUFFER_SIZE = 256) : BUFFER_SIZE_(BUFFER_SIZE) {};


  void emplace_back() // TODO: Should pass constructor parameters or even a constructor
  {
    if (!(elems_.size() % BUFFER_SIZE_))
    {
      idx_ = 0;
      buffer_ = new T[BUFFER_SIZE_];
      elems_.reserve(elems_.size() + BUFFER_SIZE_);
    }
    
    // TODO: Object constructor. Must initialize buffer_[idx]
    // createElement(buffer_[idx], parameters...);
    elems_.push_back(buffer_ + idx_++);
  }

};

通过执行new T[BUFFER_SIZE_],我获得了一个指针,该指针指向使用默认构造函数构建的连续分配的 BUFFER_SIZE_ 元素数组的第一个元素。

我想要实现的是,在这个分配完成后,用所需的参数/另一个构造函数初始化这个对象(参见 TODOs)。另外,我想避免使用复制构造函数。

鉴于我希望此类成为模板类,实现这一目标的最通用方法是什么?

【问题讨论】:

  • 听起来你可能想使用placement new
  • "指向必须在堆中连续分配的对象的指针。" - 那么为什么要存储指针呢?为什么不std::vector&lt;T&gt;
  • 我不明白为什么您需要创建更多对象只是因为您将它们直接存储在向量中而不是存储指向每个对象的指针。
  • "我不想混合使用 std::vector&lt;T&gt;std::vector&lt;T*&gt;" - 为什么?带有T 的那个将是拥有它的那个,其余的可以存储T*。只要拥有的vector 不需要重新分配它就应该是安全的,如果它必须重新分配,则需要重新创建指针向量。
  • 补充@TedLyngmo 的评论:此外,如果您使用索引而不是指针,那么使用向量重新分配也是安全的。

标签: c++ memory heap-memory


【解决方案1】:

使用std::vector 作为对象池来存储对象并使用索引而不是指针来访问对象:

#include <iostream>
#include <vector>

struct Object {
    std::string name;
    std::size_t age;

    Object(const std::string &n, std::size_t a): name(n), age(a) {}
};

template<typename T>
class Pool;

template<typename T>
class ObjectRef {
    Pool<T> &pool;
    std::size_t index;
    ObjectRef(Pool<T> &p, std::size_t i): pool(p), index(i) {}
public:
    friend Pool<T>;
    T &operator*() {
        return pool.buffer[index];
    }
    T *operator->() {
        return &pool.buffer[index];
    }
};

template<typename T>
class Pool {
    std::vector<T> buffer;
public:
    friend ObjectRef<T>;
    Pool(std::size_t s = 250) {
        buffer.reserve(s);
    }
    
    template<typename... Ts>
    ObjectRef<T> newObject(Ts ...args) {
        buffer.emplace_back(args...);
        return ObjectRef<T>(*this, buffer.size() - 1);
    }
};

int main() {
    Pool<Object> objectPool(250);
    auto objectRef = objectPool.newObject("Name", 30);
    std::cout << objectRef->name;
    Pool<int> intPool(250);
    auto intRef = intPool.newObject(30);
    std::cout << *intRef;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 2020-03-30
    • 2021-05-05
    • 2020-06-15
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多