C++ Mémoire dynamique

Comprendre le fonctionnement de la mémoire dynamique en C++ est essentiel pour devenir un programmeur C++ qualifié. La mémoire dans un programme C++ est divisée en deux parties :

  • Pile :Toutes les variables déclarées à l'intérieur d'une fonction occuperont la mémoire de pile.
  • Tas :Il s'agit de mémoire non utilisée par le programme, qui peut être utilisée pour l'allocation dynamique de mémoire pendant l'exécution du programme.

Souvent, vous ne pouvez pas prévoir à l'avance la quantité de mémoire nécessaire pour stocker des informations spécifiques dans une variable définie ; la taille de mémoire requise ne peut être déterminée qu'à l'exécution.

En C++, vous pouvez utiliser des opérateurs spéciaux pour allouer de la mémoire dans le tas pour des variables d'un type donné à l'exécution, ce qui renvoie l'adresse de l'espace alloué. Ces opérateurs sont lesnewopérateurs.

Si vous n'avez plus besoin d'espace mémoire alloué dynamiquement, vous pouvez utiliser l'opérateurdeletepour libérer la mémoire précédemment allouée par l'opérateur new.

opérateurs new et delete

Voici la syntaxe générale pour utiliser l'opérateur new afin d'allouer dynamiquement de la mémoire pour tout type de données :

new data-type;

Ici,data-typeIl peut s'agir de n'importe quel type de données intégré, y compris les tableaux, ou de n'importe quel type de données défini par l'utilisateur, y compris les classes ou les structures. Examinons d'abord les types de données intégrés. Par exemple, nous pouvons définir un pointeur vers un type double, puis demander de la mémoire, qui est allouée au moment de l'exécution. Nous pouvons utiliser l'instruction suivante :newopérateurs pour ce faire :

double* pvalue = NULL; // pointeur initialisé à null pvalue = new double; // demande de mémoire pour la variable

Si la réserve libre a été épuisée, l'allocation de mémoire peut échouer. Par conséquent, il est recommandé de vérifier si l'opérateur new renvoie un pointeur NULL et de prendre les mesures appropriées comme suit :

double* pvalue = NULL; if( !(pvalue = new double )) { cout << "Erreur : mémoire insuffisante." <<endl; exit(1); }

malloc()La fonction malloc() est apparue dans le langage C et existe toujours en C++, mais il est recommandé d'éviter d'utiliser malloc() dans la mesure du possible. Comparé à malloc(), le principal avantage de new est que new non seulement alloue de la mémoire, mais crée aussi des objets.

À tout moment, lorsque vous estimez qu'une variable dont la mémoire a été allouée dynamiquement n'est plus nécessaire, vous pouvez utiliser l'opérateur delete pour libérer la mémoire qu'elle occupe, comme indiqué ci-dessous :

delete pvalue;        // 释放 pvalue 所指向的内存

L'exemple suivant utilise le concept ci-dessus et montre comment utiliser les opérateurs new et delete :

Exemple

#include <iostream> using namespace std; int main () { double* pvalue = NULL; // pointeur initialisé à null pvalue = new double; // demander de la mémoire pour la variable *pvalue = 29494.99; // stocker la valeur à l'adresse allouée cout << "Valeur de pvalue : " << *pvalue << endl; delete pvalue; // libérer la mémoire return 0; }

Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :

Value of pvalue : 29495

Allocation dynamique de mémoire pour les tableaux

Supposons que nous voulions allouer de la mémoire pour un tableau de caractères (une chaîne de 20 caractères). Nous pouvons utiliser la syntaxe de l'exemple ci-dessus pour allouer dynamiquement de la mémoire pour le tableau, comme montré ci-dessous :

char* pvalue  = NULL;   // 初始化为 null 的指针
pvalue  = new char[20]; // 为变量请求内存

Pour supprimer le tableau que nous venons de créer, l'instruction est la suivante :

delete [] pvalue;        // 删除 pvalue 所指向的数组

Voici la syntaxe générale de l'opérateur new qui peut allouer de la mémoire pour des tableaux multidimensionnels, comme montré ci-dessous :

Tableau à une dimension

// allocation dynamique, la longueur du tableau est m int *array=new int [m]; // libérer la mémoire delete [] array;

Tableau à deux dimensions

int **array; // supposons que la première dimension du tableau ait une longueur m, et que la deuxième dimension ait une longueur n // allouer dynamiquement de l'espace array = new int *[m]; for( int i=0; i<m; i++ ) { array[i] = new int [n]; } // libérer for( int i=0; i<m; i++ ) { delete [] array[i]; } delete [] array;

Test d'instance de tableau 2D :

Exemple

#include <iostream> using namespace std; int main() { int **p; int i,j; //p[4][8] //commencer à allouer des données bidimensionnelles avec 4 lignes et 8 colonnes p = new int *[4]; for(i=0;i<4;i++){ p[i]=new int [8]; } for(i=0; i<4; i++){ for(j=0; j<8; j++){ p[i][j] = j*i; } } //afficher les données for(i=0; i<4; i++){ for(j=0; j<8; j++) { if(j==0) cout<<endl; cout<<p[i][j]<<"\t"; } } //commencer à libérer le tas alloué for(i=0; i<4; i++){ delete [] p[i]; } delete [] p; return 0; }

Tableau tridimensionnel

int ***array; // on suppose que la première dimension du tableau est m, la deuxième est n, et la troisième est h // allouer dynamiquement de l'espace array = new int **[m]; for( int i=0; i<m; i++ ) { array[i] = new int *[n]; for( int j=0; j<n; j++ ) { array[i][j] = new int [h]; } } // libérer for( int i=0; i<m; i++ ) { for( int j=0; j<n; j++ ) { delete[] array[i][j]; } delete[] array[i]; } delete[] array;

Instance de test de tableau 3D:

Exemple

#include <iostream> using namespace std; int main() { int i,j,k; // p[2][3][4] int ***p; p = new int **[2]; for(i=0; i<2; i++) { p[i]=new int *[3]; for(j=0; j<3; j++) p[i][j]=new int[4]; } //afficher les données tridimensionnelles p[i][j][k] for(i=0; i<2; i++) { for(j=0; j<3; j++) { for(k=0;k<4;k++) { p[i][j][k]=i+j+k; cout<<p[i][j][k]<<" "; } cout<<endl; } cout<<endl; } // libérer la mémoire for(i=0; i<2; i++) { for(j=0; j<3; j++) { delete [] p[i][j]; } } for(i=0; i<2; i++) { delete [] p[i]; } delete [] p; return 0; }

Allocation dynamique de mémoire pour les objets

Les objets ne sont pas différents des types de données simples. Par exemple, examinez le code suivant ; nous utiliserons un tableau d'objets pour clarifier ce concept :

Exemple

#include <iostream> using namespace std; class Box { public: Box() { cout << "Appel du constructeur !" <<endl; } ~Box() { cout << "Appel du destructeur !" <<endl; } }; int main( ) { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // supprimer le tableau return 0; }

Si vous souhaitez allouer de la mémoire pour un tableau contenant quatre objets Box, le constructeur sera appelé 4 fois ; de même, lorsque ces objets sont supprimés, le destructeur sera également appelé le même nombre de fois (4 fois).

Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :

Calling constructor!
Calling constructor!
Calling constructor!
Calling constructor!
Calling destructor!
Calling destructor!
Calling destructor!
Calling destructor!
autres extensions