2010-12-08 6 views
3

J'ai une classe A. Une bibliothèque que j'utilise alloue une quantité donnée de mémoire pour moi, sizeof A, et lui renvoie un pointeur vide.C++: Instance de classe de stockage dans la mémoire allouée

A* pObj = (A*) some_allocator_im_forced_to_use(sizeof A); 

Maintenant, comment puis-je créer une nouvelle instance de A, dans la mémoire qui vient de s'alloué?

Je l'ai essayé avec:

*pObj = A(); 

Mais cela ne fonctionne pas - le destructor se est appelé juste après le constructeur de A.

Répondre

8

Vous pouvez utiliser le placement nouveau:

A* pObj = new (some_allocator_im_forced_to_use(sizeof(A))) A; 

Ceci construit une nouvelle instance A à l'emplacement renvoyé par la fonction some_allocator_im_forced_to_use. Cette fonction doit renvoyer un void* pointant vers suffisamment de mémoire alignée de manière appropriée pour un objet A sur l'implémentation en question.

Il est probable que vous devrez appeler manuellement le destructeur pour cet objet manuellement car vous ne pourrez pas utiliser le delete pObj habituel pour le détruire.

pObj->~A(); 
// Call custom allocator's corresponding deallocation function on (void*)pObj 

Afin de détruire correctement l'objet et libérer la mémoire que vous pouvez envisager d'utiliser un shared_ptr avec un destructeur personnalisé.

3

placement utilisation nouvelle:

new (pObj) A; 

Vous aurez également besoin de détruire l'objet différemment, puisque delete suppose (à tort) que vous avez créé l'objet avec de vieux new plaine:

pObj->~A(); 
some_deallocator_im_forced_to_use(pObj); 
0

Si votre allocateur suit le modèle de std::allocator il a plusieurs méthodes:

  • allocate
  • construct
  • destroy
  • deallocate

Ils sont à peu près explicite, ce qui est important est que vous êtes responsable de les appeler:

  • dans l'ordre
  • et sans oublier toute

ou vous obtiendrez soit UB ou une fuite.

Cependant, je suis quelque peu surpris que seule la taille est requise par votre allocateur, normalement il faut également l'alignement de l'objet, sauf s'il utilise simplement l'alignement maximum possible sur la cible quel que soit l'objet à allouer.

1

Certaines personnes ont préconisé le placement nouveau. C'est dangereux, et jusqu'à présent, deux exemples d'utilisation ont omis des détails cruciaux comme l'en-tête <new>, qualifiant l'appel comme ::new ..., et comment nettoyer.

La solution sûre consiste à définir des fonctions d'allocation et de désallocation personnalisées pour votre classe ou pour une classe dérivée de votre classe. L'exemple ci-dessous montre le dernier. Notez que le destructeur virtuel est uniquement là pour prendre en charge la dérivation de classe; si vous ne dérivez pas, vous n'en avez pas besoin.

#include <stddef.h> 
#include <iostream> 

void* some_allocator_im_forced_to_use(size_t size) 
{ 
    std::cout << "Allocated " << size << " bytes." << std::endl; 
    return ::operator new(size); 
} 

void some_deallocator_im_forced_to_use(void* p, size_t size) 
{ 
    std::cout << "Deallocated " << size << " bytes." << std::endl; 
    ::operator delete(p); 
} 

struct A 
{ 
    int x_; 
    A(): x_(42) {} 
    virtual ~A() {} 
}; 

struct CustomAllocedA 
    : A 
{ 
    void* operator new(size_t size) 
    { 
     return some_allocator_im_forced_to_use(size); 
    } 

    void operator delete(void* p, size_t size) 
    { 
     some_deallocator_im_forced_to_use(p, size); 
    } 
}; 

int main() 
{ 
    A* const p = new CustomAllocedA; 

    std::cout << p->x_ << std::endl; 
    delete p; 
} 

Important: bien que ce soit « sûr » en lui-même, et bien que cet exemple est sûr, la sécurité pour votre code repose finalement sur votre commande allocateur retourner un pointeur vers la mémoire correctement aligné.

Vive & HTH.,

+0

+1 remplacant nouvel opérateur est tout à fait une bien meilleure idée que d'utiliser le placement nouveau. –

Questions connexes