Différents types de données
En terme de mémoire, il existe différents types de donnée en C++.
- Donnée statique : emplacement alloué une fois pour toute la durée du programme
- Donnée automatique (pile) : emplacement alloué à l’entrée d’un bloc (exemple : une fonction, une boucle, …) et libéré à sa sortie
- Donnée dynamique (tas) : emplacement alloué et libéré à la demande du programme, donc du développeur à l’aide des opérateurs
new
etdelete
Bref à l’aide de pointeurs.
On parle ainsi de trois classes d’allocation : statique, automatique, dynamique.
Dans cet article, nous allons étudier un peu plus en détails l’allocation / destruction de données dynamiques.
Allocation de données dynamiques
// Allocation d'un type quelconque (exemple : int, char, une classe) type *maVariable = new type; // Allocation d'un tableau de n éléments de type quelconque (exemple : int, char, une classe) // Le pointeur retourné pointe sur l'adresse du premier élément du tableau type *maVariable = new type[n];
Destruction de données dynamiques
La destruction est un tout petit peu plus compliqué puisqu’il y a plus de cas à prendre en compte : emplacement déjà libéré ou non, allocation d’un tableau d’objets ou de types classiques.
Syntaxe usuelle de l’opérateur delete :
delete adresse;
Voyons plus en détails les différents cas :
// Allocation simple int *monInt = new int; delete monInt; // Allocation multiple int *mesInt = new int[10]; delete[] mesInt; // "delete mesInt" supprime seulement l'adresse du tableau // Allocation multiple : pour un tableau d'objet MonObjet *mesObjets = new MonObjet[10]; delete[] mesObjets;
Il est conseillé de rendre nul un pointeur détruit afin de vérifier son état afin d’éviter les suppressions multiples. Les exemples précédents donneraient plutôt :
if (NULL != monPointeur) { delete monPointeur; monPointeur = NULL; }
Quelques mots sur les données automatiques
Un dernier petit détail à propos des données automatiques. Certes tout s’effectue automatiquement pour l’allocation et la destruction, mais il y a création d’une copie des objets :
- lors du passage en argument : maFunction(instanceDeMonObjet)
- lors d’une copie : nouvelleInstance = instanceDeMonObjet
- lorsque l’instance est retournée à la fin d’une fonction : return instanceDeMonObjet
Si un objet contient des pointeurs, il faut donc penser à créer un constructeur de copie (pour créer une vraie copie de ces pointeurs) afin d’éviter les destructions multiples, et donc les erreurs. Même si l’on prévoit d’utiliser cet objet via des pointeurs (donnée dynamique), il est préférable de créer tout de suite un constructeur de copie, afin d’éviter les erreurs futures.
Ah, et autre chose. D’après ce que l’on vient de dire sur la libération de données allouées dynamiquement, il apparaît que l’on n’a pas besoin de libérer un tableau alloué dynamiquement. Si on utilise directement int myArray[12]
dans le déclaration d’une classe, ou dans une méthode : pas besoin de delete[]
. Cool !
J’espère avoir l’occasion de revenir sur ce sujet afin de fixer quelques exemples sur le papier la toile 😉
One Response to Petit point sur C++ et la gestion mémoire