Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am trying to build a class to manage a std::vector<T*> of pointers to objects that must be contiguously allocated in the heap.

The problem I encountered is that building the vector as shown below leads to non contiguously allocated objects:

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

This is because two consecutive executions of new T() do not have to produce contiguous objects in memory. So the solution is to use new[] operator instead, which yielded me to this implementation:

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_++);
  }

};

By executing new T[BUFFER_SIZE_], I get a pointer to the first element of a contigously allocated array of BUFFER_SIZE_ elements built by using the Default Constructor.

What I want to achieve is, after this allocation is done, initialize this object with the desired parameters / another constructor (see TODOs). Also, I would like to avoid Copy Constructors.

Given that I want this class to be a templated class, what's the most generic way of achieve this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
209 views
Welcome To Ask or Share your Answers For Others

1 Answer

Use a std::vector as object pool to store your objects and use indexes instead of pointers to access the objects:

#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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...