2015-09-04 3 views
0

Je suis en train d'implémenter une classe conteneur (ObjectPool). Il maintient un tableau d'objets de modèle dans la mémoire contiguë. En construction, il alloue un bloc de mémoire (équivalent à (taille de l'objet template) * (taille du pool)). Lors de l'ajout de nouveaux objets au pool, il utilise l'opérateur 'placement new' pour créer un objet à une adresse mémoire spécifique (et appelle automatiquement le constructeur de l'objet modèle). Comment j'implémente la méthode ObjectPool.add(), pour accepter un objet template et l'ajouter au pool d'objets, sans appeler son constructeur deux fois (fonctionnalité implémentée dans std :: vector.push_back() par exemple) ? Pour des raisons de simplicité, dans ce cas, la classe ObjectPool ne contient qu'un objet modèle au lieu d'un tableau.Références rvalue avec placement new (fonctionnalité similaire à std :: vector.push_back)

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

Répondre

5

Si vous prenez un T_Object&&, qui doit être référenceurs à un déjà construit T_Object, et vous devez créer un nouvel objet dans votre stockage, de sorte que est un autre appel constructeur.

Vous devez quelque chose le long des lignes de 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)...); 
} 

appel comme objPool.emplace(1). À propos, la version de add prenant un T_Object&& p_object devrait construire l'objet contenu de std::move(p_object).

+0

Merci pour la réponse. J'ai ajouté _void emplace() _ méthode, et l'appel a fonctionné parfaitement. J'ai vu cette méthode dans le conteneur _std :: vector_, quand je regardais _push_back_, mais je ne comprenais pas complètement la syntaxe. Y at-il un moyen d'implémenter ceci, donc je pourrais l'appeler avec _ (FooClass (1)) _ au lieu de juste _ (1) _? –

+0

@PaulA. Vous ne pouvez pas l'avoir dans les deux sens. 'FooClass (1)' construit un 'FooClass' temporaire, donc globalement il appellera le constructeur au moins deux fois. –

+0

Comment 'std :: vector.push_back' le fait-il? Puisque, si j'appelais 'push_back' avec' FooClass (1) ', il n'appellerait le constructeur qu'une seule fois. –