Placement new

Build an objet without allocation.

new()

Voir version :

Pas de dépendances

Télécharger :

#include <iostream>
#include <new.h>

class Plouf
{
public:
    Plouf()
    {
        std::cout << "constructeur" << std::endl;
    }
    ~Plouf()
    {
        std::cout << "destructeur" << std::endl;
    }
};

int main()
{
    char buf[sizeof(Plouf)];
    void* p = buf;
    Plouf* f = new(p) Plouf();
    // delete f
    f->~Plouf();
    return 0;
}



Commentaires


  Voici un exemple assez tordu -> il est destiné aux personnes qui maitrisent la gestion mémoire.
  C'est un exemple très rarement utile.

  Imaginez que vous ayez envie d'instancier une classe A UNE ADRESSE FIXEE.

  Je m'inspire de ce site :
  http://jlecomte.ifrance.com/c%2B%2B/c%2B%2B-faq-lite/dtors-fr.html#[11.10]

  Problème posé :
  L' "inconvénient" de new (qui n'en est pas un dans 99.9999% des cas), c'est qu'il crée une zone mémoire "la ou il trouve de la place"
  --> Vous ne savez pas, quand vous appelez new, ou il va décider de ranger vos données, mais cela n'est en général pas genant.

  Mais imaginons que vous ayez envie de fixer cette adresse : vous avez envie de dire "instancie moi une classe ICI".
  C'est la qu'intervient le "placement new".

  Regardez l'exemple :
  Je crée un tableau qui fait la taille de la classe Plouf : a priori, il y a donc assez de place pour ranger une instance dans ce tableau.
  Ce tableau est fixé comme variable locale de main.

  Maintenant, j'ai envie faire un new de la classe, mais de dire que je veux que ce new s'effectue dans mon buffer.
  J'appelle la ligne :
  
  Plouf* f = new(p) Plouf();

  Cette ligne est a la meme syntaxe qu'un new "normal", mais prend un parametre en plus : c'est l'adresse a laquelle je veux instancier la classe.
  Si vous regardez le programme, vous voyez que p est l'adresse du début du buffer que j'ai réservé.
  Note : ce new N'ALLOUERA PAS LA MEMOIRE, a vous de la gérer : il fixera l'adresse a renvoyer, et appellera, comme tout bon new, le constructeur de l'objet créé.

  En tout logique, le constructeur est appelé (le cout dans le constructeur en témoigne)

  Et maintenant, comment détruire cet objet ? 
  Si je veux etre propre, je dois l'appeler.

  Habituellement, pour détruire un objet instancié avec new, j'appelle :

  delete f;

  J'ai d'ailleurs mis la ligne en commentaire : réactivez la, et désativez l'appel au destructeur en dessous.

  Si vous lancez le programme, vous allez planter : en effet, vous demandez la destruction de l'instance, donc l'appel au destructeur + la libération de sa mémoire.
  Or sa mémoire, qu'est ce que c'est ? c'est un tableau local, qui lui sera détruit a la fin de la fonction : destruction 2 fois de la meme adresse = plantage.
  Et destruction d'une adresse locale : aïe aïe...

  Donc enlevez le delete f.
  le delete appelle le destructeur + libere la mémoire.

  Si je veux etre propre, il faut que le destructeur soit appelé, et ensuite, laisser la fin de la fonction détruire sa variable locale :
  C'est pour cela que dans ce cas la, et c'est un des tres rares cas ou on va explicitement appeler le destructeur, avec la ligne :

  f->~Plouf();

  Et avec cela plus de soucis.
  On récapitule :
  - création de la mémoire de l'objet avec le tableau statique
  - appel constructeur avec le placement new.
  - appel explicite du destructeur
  - libération de la mémoire a la fin de la fonction automatiquement (variable locale)


  Note : Utilisez 
  #include <new.h> 
  pour utiliser les placement new.


Laissez un commentaire / post a comment