Gestion de mémoire dynamique : new et delete
Allocations sur le tas, usage sûr de new/delete et préambule vers RAII.
En C++, la mémoire est divisée en deux régions principales : la pile (Stack) et le tas (Heap).
Tandis que la pile est gérée automatiquement, la mémoire du tas est contrôlée manuellement par le programmeur.
La gestion dynamique de la mémoire est utilisée pour allouer et libérer de la mémoire pendant l’exécution du programme.
Dans cet article, nous allons examiner en détail l’utilisation de new et delete pour la gestion dynamique de la mémoire.
1. Différence entre la pile et le tas
| Caractéristique | Pile (automatique) | Tas (dynamique) |
|---|---|---|
| Gestion | Automatique (par le compilateur) | Manuelle (par le programmeur) |
| Durée de vie | Supprimée automatiquement à la fin de la fonction | Reste jusqu’à être supprimée manuellement |
| Vitesse | Très rapide | Plus lente (allocation dynamique) |
| Taille de la mémoire | Limitée | Beaucoup plus grande |
| Utilisation | Variables locales | Objets et tableaux dynamiques |
2. Allocation de mémoire avec le mot-clé new
L’opérateur new alloue dynamiquement de la mémoire sur le tas et retourne l’adresse de la zone allouée.
Cette adresse est généralement assignée à une variable pointeur.
#include <iostream>
using namespace std;
int main() {
int *ptr = new int; // alloue de la mémoire pour un entier
*ptr = 42;
cout << "Valeur : " << *ptr << endl;
delete ptr; // libère la mémoire
ptr = nullptr; // sécurise le pointeur
}
Remarque : la mémoire allouée avec new doit être libérée manuellement avec delete.
Sinon, une fuite de mémoire (memory leak) se produit.
3. Tableaux dynamiques avec new
Pour créer un tableau dynamique, on utilise new[].
Sa taille peut être déterminée à l’exécution.
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Combien d’éléments ? ";
cin >> n;
int *tableau = new int[n]; // crée un tableau de n éléments
for (int i = 0; i < n; i++)
tableau[i] = (i + 1) * 10;
cout << "Tableau : ";
for (int i = 0; i < n; i++)
cout << tableau[i] << " ";
delete[] tableau; // libère la mémoire
tableau = nullptr;
}
L’utilisation de delete[] est essentielle ;
l’opérateur delete simple est réservé aux variables uniques, pas aux tableaux.
4. Étapes de l’allocation et de la libération de mémoire dynamique
- new → alloue de la mémoire sur le tas.
- Pointeur → stocke l’adresse de la mémoire allouée.
- Les données sont traitées ou remplies.
- delete / delete[] → libère la mémoire allouée.
- pointeur = nullptr → empêche les pointeurs pendants (dangling pointers).
5. Qu’est-ce qu’une fuite de mémoire ?
Lorsqu’une mémoire allouée dynamiquement n’est pas libérée, des blocs de mémoire inutilisés s’accumulent. Ce phénomène s’appelle une fuite de mémoire et peut provoquer de graves problèmes de performance dans les programmes à long terme.
void MauvaisExemple() {
int *p = new int(10);
// delete p; // Oublié ! Fuite de mémoire
}
Solution : toujours libérer la mémoire avec delete.
6. nullptr et sécurité mémoire
Avant C++11, les pointeurs nuls étaient généralement représentés par NULL.
En C++ moderne, il est recommandé d’utiliser le mot-clé nullptr, plus sûr et typé.
int *p = nullptr;
if (p == nullptr) {
cout << "Le pointeur ne pointe vers aucune adresse." << endl;
}
L’utilisation de nullptr aide à éviter les accès mémoire invalides et les erreurs de segmentation.
7. Utiliser la mémoire dynamique avec des fonctions
La mémoire peut être créée dynamiquement et passée à une fonction. Cette approche est particulièrement utile avec les tableaux dynamiques.
void Remplir(int *p, int n) {
for (int i = 0; i < n; i++)
p[i] = (i + 1) * 2;
}
int main() {
int *tableau = new int[5];
Remplir(tableau, 5);
for (int i = 0; i < 5; i++)
cout << tableau[i] << " ";
delete[] tableau;
}
8. Créer un objet avec new
L’opérateur new peut être utilisé non seulement pour les types de base,
mais aussi pour créer des objets de classe.
#include <iostream>
using namespace std;
class Etudiant {
public:
string nom;
Etudiant(string n) : nom(n) {
cout << nom << " créé." << endl;
}
~Etudiant() {
cout << nom << " supprimé." << endl;
}
};
int main() {
Etudiant *p = new Etudiant("Ali");
delete p; // le destructeur est appelé
}
Supprimer un objet créé avec new appelle automatiquement son destructeur.
9. Pointeurs intelligents (approche C++ moderne)
Avec C++11, les pointeurs intelligents (smart pointers) ont été introduits comme alternative
à la gestion manuelle de la mémoire avec delete.
Ils permettent une gestion automatique de la mémoire.
- std::unique_ptr → propriété unique (non copiable)
- std::shared_ptr → propriété partagée (compteur de références)
- std::weak_ptr → référence faible à un pointeur partagé
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> p = make_unique<int>(100);
cout << *p << endl; // 100
}
Les pointeurs intelligents libèrent automatiquement la mémoire lorsque l’objet sort du champ de portée, éliminant ainsi le risque de fuite de mémoire.
10. TL;DR
new→ alloue de la mémoire sur le tas et retourne son adresse.delete→ libère la mémoire (variable unique).new[] / delete[]→ utilisés pour les tableaux dynamiques.nullptr→ définition sûre d’un pointeur nul.- Pour éviter les fuites de mémoire, chaque
newdoit être accompagné d’undelete. std::unique_ptretstd::shared_ptrsont des alternatives modernes.- Tous les exemples peuvent être compilés dans Visual Studio 2022 ou GCC 11+.