1 Programmation en C++ Cycle de vie ● La vie d'un objet ● Destructeur ● Gestion de mémoire dynamique
2 Le cycle de vie d'un objet void UneFonction() { // Créer deux points Point point1(0, 0); Point point2(2, 3); // Calculer et imprimer leur distance std::cout << point1.Distance(point2) << std::endl; } Des objets « naissent » quand on appelle leurs constructeurs ● Les objets ont un cycle de vie – Nous avons déjà appris comment créer un objet: Que se passe-t-il maintenant? ● Après avoir quitté la fonction (hors de portée) les deux points ont été détruits automatiquement
3 Les types de cycle de vie d'un objet ● Le cycle de vie d'un objet = le temps pendant lequel la mémoire est allouée à l'objet, ou le temps entre la création et la destruction de l'objet ● Les trois types de cycle de vie d'un objet: – Automatique – l'objet est créé à sa déclaration et est détruit lorsqu'il devient hors de portée, lorsque l'on quitte le contexte qui le déclarait – Dynamique – l'objet est créé et détruit n'importe quand sous le contrôle du programmeur – Statique - l'objet est créé une fois et n'est détruit que quand le programme se termine ● Ne pas confondre avec la gestion automatique ● Nous n'allons pas discuter ce type en détails dans notre cours
4 Les types de cycle de vie d'un objet - Exemples Gestion automatique: void UneFonction() { // Créer un point Point point(0, 0); // Une utilisation du point } void UneAutreFonction() { // Créer un point Point* point1 = new Point(0, 0); // Une utilisation du point delete point1; } Gestion dynamique: La mémoire allouée par « point » est libérée automatiquement La mémoire allouée par « point » est libérée par le programmeur ● L'opérateur new effectue l'allocation de mémoire et l'appel du constructeur ● L'opérateur delete effectue l'appel du destructeur puis la libération de la mémoire ● La règle de programmation avec gestion de mémoire dynamique est de toujours vérifier que chaque « new » a son « delete »
5 Destructeur... Le destructeur est la fonction spéciale de la classe appelée juste avant que l'objet soit détruit class class-name { public: // fonctions pour construire l'objet // fonction appelée quand on détruit l'objet // fonctions pour manipuler l'objet // fonctions pour accéder à l'état de l'objet private: // fonctions pour utilisation intérieure // données membres }; class Point { public: // fonctions pour construire l'objet Point(); Point(float x, float y); // fonction appelée quand on détruit l'objet ~Point(); // autres fonctions private: // données membres float m_x; float m_y; }; – Il y a un seul destructeur dans la classe
6... Destructeur Point::~Point() { /// Le destructeur de la classe std::cout << “Point est détruit” << std::endl; } – Si on exécute notre fonction après avoir ajouté notre destructeur, nous allons apercevoir des messages « Point est détruit » – La plupart du temps le destructeur est utilisé à libérer la mémoire qui a été allouée dynamiquement par l'objet ● Comme les données membres de notre classe Point sont gérées par gestion automatique, alors le destructeur n'a rien à faire
7 Gestion de mémoire dynamique class Point { public: Point(float x, float y); Point(); ~Point(); private: // données membres float* m_x; float* m_y; }; Point::Point(float x, float y) : m_x( new float(x) ), m_y( new float(y) ) { /// Le constructeur avec gestion de mémoire /// dynamique } Point::Point() : m_x(0), m_y(0) { /// Le constructeur par défaut } Point::~Point() { /// Le destructeur delete m_x; delete m_y; } L'initialisation de pointeurs est importante pour que delete s'accomplisse correctement Les données membres déclarées comme pointeurs
8 Les types fondamentaux, les tableaux ● Les variables simples (int, float,...) ont les mêmes types de vie Gestion automatique: void UneFonction() { // Un numéro int num = 153; // Un tableau int tab[20]; for ( int i=0; i<20; i++ ) tab[i] = i; // Un tableau des objets Point points[10]; } void UneAutreFonction() { // Un numéro int* num = new int(153); delete num; // Un tableau int* tab = new int[20]; for ( int i=0; i<20; i++ ) tab[i] = i; delete [ ] tab; // Un tableau des objets Point* points = new Point[10]; delete [ ] points; } Gestion dynamique: Attention à la notation delete [ ] pour un tableau Il est conseillé d'utiliser les conteneurs STL à la place de tableaux intégrés pour éviter les problèmes dus à la taille fixe des tableaux intégrés