TD 7 C++: allocation dynamique; construction/destruction.

Instructions spéciales

Ce TD est mis en ligne dès le Mercredi 26 Octobre, mais la séance est reportée au Lundi 31 de 17h à 19h:

Rappels


Exercice 1: Références: suite et fin

  1. Listez dans un fichier 1.1.txt, par ordre croissant, les indices X des fonctions Return42_X valides (qui compilent!):

    Code C++ à interpréter
    Le fichier 1.1.txt devra ressembler contenir une seule ligne qui ressemblera à ça:
    2, 4, 8, B, D
    Vérifiez avec le script 1.1.sh: bash 1.1.sh

    RENDU: 1.1.txt

    Vous aurez l'explication au tableau!

  2. Classez les struct suivantes par ordre croissant de leur taille (en octets!). Ce qui correspond à sizeof(..).

    struct A {
      int x;
    };
    struct B {
      int* x;
    };
    struct C {
      static int x;
    };
    struct D {
      int& x;
    };
    struct E {
      bool& x;
    };
    struct F {
      bool x;
    };
    struct G {
      int** x;
    };


    Si deux struct sont de tailles égales, vous les garderez dans l'ordre alphabetique.

    RENDU: 1.2.txt qui contiendra une ligne au format:
    A, B, C, D, E, F, G
    ... avec le bon ordre bien sûr.


Exercice 2: Construction/Destruction

  1. Examinez le code ci-dessous, mis sur 2 colonnes (télécharger: 2.1.cc):
    #include <iostream>
    
    using namespace std;
    
    class A {
     public:
      A() : x_(0) {
        cout << "Constructing A() @" << this << endl;
      }
      A(int x) {
        x_ = x;
        cout << "Constructing A(" << x << ") @" << this << endl;
      }
    
      ~A() {
        cout << "~A(): x = " << x_ << ", @" << this << endl;
      }
    
     private:
      int x_;
    };
    int main() {
      cout << "Starting" << endl;
      A a = 123;
      {
        A a;
        A* aa = new A(456);
      }
      for (int i = 0; i < 2; i++) {
        A a(i);
      }
      A* a_ptr[3] = {NULL, NULL, NULL};
      for (int i = 0; i < 3; i++) {
        a_ptr[i] = new A(i);
      }
    
      for (int i = 0; i < 3; i++) {
        delete a_ptr[i];
      }
    
      A yop[2];
    
      // Where is the memory leak ??
    }
    Essayez de simuler son execution vous-même, en notant sur une feuille de papier ce que le programme va imprimer.

    Explication au tableau!


Exercice 3: Tableaux dynamiques

  1. Implémentez dans un fichier 3.1.cc la classe Array déclarée ci-dessous (telécharger 3.1.h):
    // This class represents an array of doubles, with a fixed capacity
    // determined at construction.
    class Array {
     public:
      // The array will be empty at construction, but all the memory 
      // necessary to store up to "capacity" doubles will already be allocated.
      Array(int capacity);
    
      // It is important to clean up the memory at destruction!
      ~Array();
    
      // Returns the current size (i.e. number of elements) of the array.
      int size() const;
    
      // Returns the *mutable* element at index #i.
      double& operator[](int i);
    
      // Adds an element at the last position of the array.
      void push_back(double x);
    
      // Removes the last element of the array.
      void pop_back();
    
     private:
      int size_;
      double* data_;
    };
    Testez-la:
    rm 3.tar.gz
    wget --no-cache http://fabien.viger.free.fr/c++/td7/3.tar.gz
    tar xf 3.tar.gz
    make 3.1
    RENDU: 3.1.cc

  2. (**) On va à présent faire une véritable allocation dynamique: on allouera la mémoire selon les besoins.
    Attention: on veut garder une complexité amortie en O(1): le coût moyen d'une opération doit être O(1), et la place memoire utilisé devra être O(N), où N = nombre d'éléments.

    Copiez 3.1.h dans 3.2.h, enlever l'argument capacity du constructeur, et implémentez 3.2.cc

    RENDU: 3.2.h, 3.2.cc