Changes between Version 1 and Version 2 of 2010CaoTme1


Ignore:
Timestamp:
Feb 19, 2010, 1:23:07 AM (15 years ago)
Author:
jpc
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • 2010CaoTme1

    v1 v2  
    1 = Objets simples en C++ =
    21
     2= Mon Premier Objet en C++ =
     3
     4== La Classe Vector ==
     5
     6L'objectif de la classe {{{vector}}} est de fournir des objets se comportants de
     7façon identiques aux tableaux C, mais avec l'avantage d'une gestion transparente
     8de l'allocation mémoire. Dans le cadre de ce TME, nous travaillerons sur un
     9tableau d'entier.
     10
     11=== Construction ===
     12
     13Un {{{Vector}}} devra pouvoir être construit à partir de rien (il sera vide)
     14ou à partir d'un tableau C ordinaire. On fournira aussi une implémentation
     15du constructeur par copie.
     16
     17{{{
     18  int  ordered[] = { 0, 1, 2, 3, 5 };
     19  Vector v1 ( ordered, 5 );
     20}}}
     21
     22En plus des construct
     23 
     24=== Stratégie d'allocation mémoire ===
     25
     26Plutôt que d'allouer un tableau sous-jacent de la taille exacte du nombre des
     27éléments contenus, le {{{Vector}}} réserve à l'avance de l'espace libre.
     28Ceci afin de limiter le nombre d'opérations de réallocation ainsi que de
     29trop fragmenter la mémoire.
     30
     31Nous sommes donc amenés à distinguer deux quantitées:
     32 * Le nombres d'élements réellement utilisés du {{{Vector}}}, ce nombre sera
     33   indiqué par la méthode {{{size()}}}.
     34 * Le nombres d'élements que peut contenir le {{{Vector}}} ''sans avoir à être
     35   ré-alloué''. Nombre indiqué par la méthode {{{capacity()}}}.
     36
     37Le tableau sous-jacent du {{{Vector}}} aura une taille strictement croissante.
     38Il se ré-allouera dans des zones mémoires de plus en plus grandes.
     39
     40  '''Attention:''' lors d'une ré-allocation, la zone mémoire précédemment occupée
     41  doit être libérée, ainsi qu'a la destuction de l'objet.
     42
     43La taille du vecteur doublera (sur un multiple de 2) à chaque réallocation. Ce qui
     44revient à dire qu'un {{{Vector}}} ne pourra avoir que des tailles de: 0, 1, 2, 4, 8,
     4516, 32, 64, ...
     46
     47Cas particulier: si l'on connaît la taille ''à priori'' du vecteur, on dispose d'une
     48méthode {{{resize(size_t)}}} pour le dimensionner directement à la bonne taille.
     49
     50L'allocation mémoire sera gérée grâce aux deux méthodes privées suivantes:
     51 * {{{_resize(size_t)}}}, assure la ré-allocation pour n'importe quelle capacité,
     52   ne fait rien si on demande une diminition de celle-çi. Dans ce dernier cas,
     53   on affichera le message d'avertissement suivant:
     54     {{{[WARNING] Vector::_resize() cowardly refusing to shrink (16 to 7)}}}
     55 * {{{_growPolicy(size_t newcapacity)}}}, calcule la nouvelle capacité nécessaire pour
     56   pouvoir stocker {{{newcapacity}}}.
     57 
     58=== Ajout, retrait et accès aux éléments ===
     59
     60Dans un premier temps, l'ajout et le retrait d'élément se fera uniquement en fin
     61de tableau avec les méthodes suivantes:
     62 * {{{void  push_back(int)}}}, ajoute un élément.
     63 * {{{int   pop_back()}}}, renvoie et retire le dernier élément. Dans le cas ou le {{{Vector}}}
     64   est vide, afficher le message suivant:
     65     {{{[ERROR] Vector::pop_back(): vector is empty."}}}
     66
     67L'accès aux éléments se fera par l'intermédiaire de l'opérateur d'accès indexé.
     68Si l'index est hors borne, afficher le message:
     69  {{{[ERROR] Vector::operator[](): Index 12 is out of bound (10)"}}}
     70
     71=== Identificateur ===
     72
     73On désire, de plus marquer chaque {{{Vector}}} avec un identificateur unique,
     74proposer une mécanique. La méthode {{{size_t id()} renverra l'identificateur
     75du vecteur.
     76
     77=== Affichage d'un {{{Vector}}} dans un flot de sortie ===
     78
     79Ajouter la mécanique nécessaire à l'affichage d'un vecteur dans un flot. On désire
     80obtenir l'affichage suivant:
     81  {{{<Vector id:0 5/8 [0 1 2 3 5]>}}}
     82Ou les informations sont respectivement, l'indentificateur du vecteur, le nombre
     83d'élements actuellement contenus, la capacité puis les valeurs des éléments.
     84 
     85=== Echange du contenu de deux {{{Vector}}} ===
     86
     87On réalisera une fonction {{{void swap(Vector&)}}} qui échangera le contenu de deux
     88vecteurs. Astuce: comment utiliser cette fonction pour libérer la mémoire occupée
     89par un vecteur?
     90
     91=== Petit Programme de test ===
     92
     93{{{
     94#include <iostream>
     95using namespace std;
     96
     97#include "Vector.h"
     98
     99int main ( int argc, char* argv[] )
     100{
     101  int  ordered[] = { 0, 1, 2, 3, 5 };
     102  Vector v1 ( ordered, 5 );
     103
     104  cout << "v1[0] = " << v1[0] << endl;
     105  cout << "v1[5] = " << v1[5] << endl;
     106  cout << "v1 " << v1 << endl;
     107
     108  Vector v2;
     109  v2.reserve ( 5 );
     110  for ( size_t i=0 ; i<5 ; ++i ) v2.push_back ( 4-i );
     111  cout << "v2 " << v2 << endl;
     112  v2.push_back ( 5 );
     113  cout << "v2 " << v2 << endl;
     114  for ( size_t i=0 ; i<8 ; ++i ) v2.pop_back ();
     115  cout << "v2 " << v2 << endl;
     116
     117  cout << "Number of allocated vectors:" << Vector::getMaxId() << endl;
     118
     119  return 0;
     120}
     121}}}
     122
     123
     124== Iterateur ==
     125
     126En première approximation, un ''iterateur'' (ou {{iterator}}) est une classe
     127conçue de façon à imiter le comportement d'un pointeur.
     128
     129La classe {{{iterator}} comportera deux membres:
     130 * {{{_vector}}}, le vecteur auquel il se rapporte. Peut être {{{NULL}} s'il n'est
     131   apparié à aucun {{{Vector}}}
     132 * {{{_index}}}, l'élement actuellement pointé dans le vecteur. Si l'itérateur est
     133   invalide, on renverra le message suivant:
     134     [ERROR] Vector::iterator::operator*(): invalid iterator.
     135
     136La class {{{Vector}}} s'enrichi alors de deux méthodes supplémentaires:
     137 * {{{iterator begin()}}}, renvoie un iterateur sur le premier élément du
     138   vecteur.
     139 * {{{iterator end()}}}, renvoie un iterateur pointant sur un élement situé
     140   ''virtuellement'' après le dernier élément du vecteur.
     141
     142Considérant le code suivant:
     143{{{
     144  Vector::iterator it  = v1.begin ();
     145  Vector::iterator end = v1.end   ();
     146
     147  cout << "v1:";
     148  for ( ; it != end ; ++it ) {
     149    cout << " " << *it;
     150  }
     151  cout << endl;
     152
     153  it  = v1.begin();
     154  it += 3;
     155  cout << "iterator begin()+3 on v1: " << *it << endl;
     156  while ( not v1.empty() ) v1.pop_back ();
     157  cout << "iterator begin()+3 on v1: " << *it << endl;
     158}}}
     159Ecrire le code des itérateurs de vecteurs.
     160
     161=== Classes imbriqués ===
     162
     163Il est possible d'imbriquer une classe dans une autre, mise en pratique dans le
     164cas d'un itérateur:
     165{{{
     166class Vector {
     167  public:
     168    class Iterator {
     169       public:
     170         Iterator ( Vector* v=NULL, size_t index=0 );
     171    };
     172  // ...
     173};
     174
     175Vector::Iterator::Iterator ( Vector* v, size_t index )
     176{ }
     177}}}
     178
     179Il faut simplement répéter le préfix {{{Vector::}}} devant les définitions des
     180fonctions membres à l'extérieur de la classe.