2

I am implementing a container class (ObjectPool). It maintains an array of template objects in contiguous memory. On construction, it allocates a block of memory (equivalent to (size of template object)*(pool size)). When adding new objects to the pool, it uses 'placement new' operator to create an object at a specific memory address (and automatically call template object's constructor).

How do I implement the ObjectPool.add() method, to accept a template object and add it to the object pool, without calling it's constructor twice (functionality as implemented in std::vector.push_back() for example)?

For simplicity, in this case, ObjectPool class contains only one template object instead of an array.

class FooClass
{
public:
    FooClass(int p_testValue) : m_testValue(p_testValue)
    {
        std::cout << "Calling constructor: " << m_testValue << std::endl;
    }

    int m_testValue;
};

template <class T_Object>
class ObjectPool
{
public:
    ObjectPool()
    {
        // Allocate memory without initializing (i.e. without calling constructor)    
        m_singleObject = (T_Object*)malloc(sizeof(T_Object));
    }

    // I have tried different function arguments (rvalue reference here, amongs others)
    inline void add(T_Object &&p_object)
    {
        // Allocate the template object
        new (m_singleObject) T_Object(p_object);
    }

    T_Object *m_singleObject;
};

int main()
{
    ObjectPool<FooClass> objPool;
    objPool.add(FooClass(1));
}

1 Answer 1

5

If you take a T_Object&&, that must be refering to an already-constructed T_Object, and then you need to create a new object in your storage, so that's another constructor call.

You need something along the lines of emplace_back:

template<class... Args>
void emplace(Args&&... args)
{
    // Allocate the template object
    ::new (static_cast<void*>(m_singleObject)) T_Object(std::forward<Args>(args)...);
}

Call it as objPool.emplace(1).

By the way, the version of add taking a T_Object&& p_object should construct the contained object from std::move(p_object).

4
  • Thank you for the answer. I've added void emplace() method, and calling it worked perfectly. I have seen this method in the std::vector container, when I was looking at push_back, however I did not understand the syntax completely. Is there a way to implement this, so I could call it with (FooClass(1)) instead of just (1)?
    – Paul A.
    Commented Sep 4, 2015 at 1:43
  • @PaulA. You can't have it both ways. FooClass(1) constructs a temporary FooClass, so overall it will call the constructor at least twice.
    – T.C.
    Commented Sep 4, 2015 at 2:27
  • How does std::vector.push_back do it? Since, if I would call push_back with FooClass(1), it would only call the constructor once.
    – Paul A.
    Commented Sep 4, 2015 at 2:33
  • 2
    @PaulA. I doubt it, unless you didn't instrument the constructors properly.
    – T.C.
    Commented Sep 4, 2015 at 2:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.