Mardi 04 octobre 2016

Résumé

Notes d’introduction au C++ et à sa bibliothèque standard générique (STL) pour préparation aux TPs de LIFLC et LIFTL :

  1. on présente un algorithme de fermeture d’un système implicatif relativement simple issu du cours de fondements des bases de données (LIFBDW2);

  2. on introduit la syntaxe spécifique du C++ et l’essentiel des bases conceptuelles nécessaires à une réalisation de cet algorithme avec la STL.

1. Introduction

1.1. Faciliter la réalisation d’algorithmes

Pourquoi cette introduction au C++
  • En licence (et ailleurs) les algorithmes sont spécifiés formellement en pseudo-code;

  • Pour transformer "sereinement" ces algorithmes en véritables programmes, on a intérêt à :

    • écrire rapidement des programmes clairs et concis, proches de leur spécifications formelles en pseudo-code;

    • ne pas réinventer la roue des structures efficaces, éviter les difficultés techniques (e.g., gestion de la mémoire);

    • se concentrer sur l’algorithmique :

      • quelle structure, pourquoi, quelle stratégie de parcours, quelle est la complexité des opérations…

Note Le C++ et sa bibliothèque standard générique (Standard Template Library, STL) fournissent les éléments suffisants pour implémenter les algorithmes de LIFLC et LIFLF en TP.
L’algorithme de fermeture d’un ensemble d’attributs (LIFBDW2)
./Images/LIF10-DefinitionDF.png
./Images/LIF10-InferenceDF.png
Questions ([Reponses])

Comment, dans le langage C que vous connaissez :

  1. représenter un ensemble d’attributs ?

  2. calculer la taille, l’union, la différence, l'égalité, l’inclusion d’ensembles (d’attributs) ?

  3. représenter une Dépendance Fonctionnelle (DF) ?

  4. réutiliser les primitives des ensembles d’attributs pour des ensembles de DFs ?

Un effort considérable est nécessaire à la réalisation de ces primitives, sans encore avoir encore commencé à écrire l’algorithme à proprement parlé ! Cette introduction au C++ a pour objectif de diminuer cet effort pour mieux se concentrer sur les parties intéressantes.

1.2. Les multiples facettes du C++

Le C++ un langage multi-paradigmes :
  • Programmation impérative en C "étendu" (e.g., tout le C, les références) : que vous connaissez en licence;

  • Programmation orientée objet (e.g., classes, héritage multiple, encapsulation, polymorphisme, string, cin/cout), que vous connaissez en DUT;

  • Programmation générique (e.g., templates, conteneurs, meta-programming);

  • Programmation fonctionnelle (e.g., pointeurs sur fonctions, functors, lambda abstractions).

Important On va garder un style impératif, en tirant profit des nouvelles possibilités du C++ sur le C lorsque c’est intéressant, clair et facile.
Important Le C++ est un langage très riche, difficile, avec lequel il est facile de se "tirer une balle dans le pied".
Ce que l’on va voir
  • Se servir naturellement des classes et des objets

  • Concevoir des classes et des objets et comprendre les détails

  • Se servir naturellement de la STL

  • Concevoir des classes génériques et comprendre les détails

  • Les arcanes du C++

Important On va survoler de nombreux concepts nouveaux : leur usage est censé être naturel et peut grandement simplifier la programmation.

2. La réalisation de la fermeture

Organisation de la suite
  • Présentation de fonctionnalités utiles du C++

  • Illustration avec la réalisation de l’algorithme de fermeture d’un ensemble d’attributs (sloc = Single Line Of Code):

    • Directives : 8 slocs

    • Structures : 13 slocs

      • Définitions des types att_t, data_t, df_t et df_set_t : 7 slocs

      • operator == et operator < : 6 slocs

    • Entrées et sorties de structures : 45 slocs

      • Sorties (ostream& operator<<) : 14 slocs

      • Entrées (istream& operator>>, readDFs) : 31 slocs

    • Algorithmes : 24 slocs

      • closure : 12 slocs

      • models : 4 slocs

      • schema : 8 slocs

    • main() : 40 slocs

  • Au total : (8 + 40 + 45) + (13 + 24) = 130 slocs

Note
Réponses en C++ aux [Questions] précédentes
  1. Avec char pour un attribut, on déclarera un set<char>;

  2. Les fonctions size, set_union, set_difference, == et includes existent dans la librairie standard du C++ et sont disponibles pour set<char>;

  3. On utilisera une struct qui contient deux membres tous deux de type set<char>;

  4. Les fonctions sont en fait disponibles pour set<T> pour peu que T soit ordonnable. C’est le cas des types primitifs

Aucun pointeur n’est utilisé dans le code qui suivra, on évite ainsi la possiblement difficile gestion de la mémoire. Il faut au total (13 + 24) = 37 lignes de C++ utilisant la STL pour implémenter l’algorithme proprement dit.

2.1. Programmation orientée objet

Qu’est ce qu’un objet ?
  1. C’est une structure où la notation pour l’accès aux membres est aussi utilisable pour les fonctions;

  2. C’est une structure qui comporte des données mais aussi des méthodes et des fonctions;

  3. C’est l’encapsulation et le contrôle de accès aux données;

  4. C’est un contexte local d’exécution.

Note La STL est une bibliothèque "d’objets génériques", il faut donc se familiariser avec la notation et les usages et pas plus.
L’accès aux méthodes des objets

Pour appeler une méthode qui insère un élément x dans une collection s :

  • Impératif : on aurait s comme paramètre explicite d’une méthode insert(x, s);

  • Orienté objet : on aurait un appel d’une méthode de l’objet s.insert(x);

    • Sous-entendu "insert peut accéder aux données contenues dans s et à ses autres fonctions".

Extrait de code : affichage des élements d’un conteneur
  set<int> myset, otherset;
  //deux ensembles (vides)

  for (int i=1; i<=5; i++)
    myset.insert(i*10);
  // myset={10, 20, 30, 40, 50}

  ret = myset.insert(20);
  //ajout d'un élément déjà présent : pas d'effet

  ret = myset.insert(60);
  //ajout d'un élément nouvel élement

  otherset = myset;
  //copie de myset dans otherset={10, 20, 30, 40, 50, 60}

2.2. La bibliothèque standard générique STL

Indépendance entre algorithmes et conteneurs grâce aux itérateurs
./Images/in2p3.fr_STL.gif
  • Les conteneurs (e.g., tableaux dynamiques, listes, piles, ensembles, multi-ensembles) sont dotés de fonctions pour les manipuler et fournissent des itérateurs [Conteneurs];

  • Les itérateurs sont moralement des pointeurs sur les éléments des conteneurs, qui permettent de faire abstraction des structures de données concrètes (e.g., quel type d’arbre : balancé, binaire, rouge et noir…) utilisées pour la réalisation [Iterateurs];

  • Les algorithmes (e.g., copier, rechercher, remplacer, compter) prennent en paramètres des itérateurs et sont entièrement définis avec eux sans autres références à la structure concrète [Algorithmes].

Note Le même algorithme est réutilisable avec plusieurs structures de données.

2.2.1. Les conteneurs

Les conteneurs standards
  • Conteneurs séquentiels :

    • L’ordre d’insertion dans le conteneur donne l’ordre dans lequel les éléments sont accessibles;

    • e.g., tableaux dynamiques (vector<T>), listes (list<T>), piles à doubles entrées (dequeue<T>).

  • Conteneurs associatifs :

    • On fait correspondre une valeur à une clef, l’ordre d’insertion n’est pas respecté lors de l’accès;

    • e.g., ensembles (set<T>), multi-ensembles ou "sacs" (multiset<T>), applications "fonctionnelles" (map<T>), multi-applications ou "relations" (multimap<T>).

./Images/Jak_Kirman_Containers.gif
Note Les conteneurs permettent de s’abstraire (jusqu'à l’oublier) la gestion dynamique de la mémoire.
Important A chaque conteneur le #include qui lui correspond !
Une grande parties des fonctionnalités utiles sont déjà présentes dans les conteneurs standards, exemple avec set<T> :
set();
//un ensemble vide
set(const set<T>& x);
//un ensemble obtenu par copie d'un précédent
set (Iterator first, Iterator last);
//un ensemble obtenu par copie des élément d'un conteneur quelconque

insert(const T& x);
//on ajoute un nouvel élément
insert(Iterator first, Iterator last);
//on ajoute une collection de nouveaux éléments

erase(const T& x);
//on supprime l'élément x s'il existe

size();
//le nombre d'élément dans l'ensemble
empty()
//l'ensemble est-il vide ?
Tip
  • Pour savoir ce qui est disponible pour un conteneur, e.g., set voir http://www.cplusplus.com/reference/stl/set/

  • Pour simplifier la gestion de la mémoire privilégier tant que possible :

    • Les chaînes de caractères string aux char*;

    • Les références (&) aux pointeurs (*);

    • Les conteneurs aux structures faites maison.

Tip
Conception : choix des conteneurs

Bien choisir ses structures de données (e.g., vector<T>, set<T>, list<T>) !

Déclarer et combiner des conteneurs
typedef char att_t;
//pour éviter de trop dépendre du type concret des attributs
typedef set<att_t> data_t;
//un ensemble d'attributs

struct df_t {
//une df (dépendance fonctionnelle) est une paire d'ensemble d'attributs
    data_t _src;
    data_t _dst;
};

bool operator == (const df_t &lhs, const df_t &rhs){
  //des DFs son égales si elles ont exactement les mêmes membres
  return (lhs._src == rhs._src && lhs._dst == rhs._dst);
}
bool operator < (const df_t &lhs, const df_t &rhs){
  //comme on a besoin d'un ordre total sur les DFs, on utilise l'ordre lexicograhique
  return (lhs._src < rhs._src || (lhs._src == rhs._src && lhs._dst < rhs._dst));
}

typedef set<df_t> df_set_t ;
//un ensemble de dépendances pour des raisons d'efficacités
//il est nécessaire d'avoir défini "bool operator <" pour le type des éléments, ici df_t
Important Les opérateurs (e.g., ==, < etc.) utilisés en notation infixe ont une déclaration particulière.
Tip
Les initializer lists
  • Une nouveauté du standard C++11;

  • Nécessite le paramètre -std=c++11 (ou -std=c++0x sur les anciennes versions de g++);

  • Permet d’initialiser dynamiquement n’importe quelle container avec la notation pour les tableaux statiques {1, 2, 3}.

  df_t f;
  f._src.insert('C');
  f._dst.insert('D');
  f._dst.insert('A');
  cout << "f : " << f << endl;
  // affiche "f : C -> AD"

  df_t g;
  g._src = {'B'};
  g._dst = {'C', 'A'};
  cout << "g : " << g << endl;
  // les insertions sont remplacées par des initializer lists
  // on obtient le même résultat

  df_set_t sigma = {f, g};
  // on déclare un ensemble de DFs et on l'initialise
  cout << "{f,g} : " << endl << sigma;
  // affiche "{f,g} :
  //          B -> AC
  //          C -> AD"

2.2.2. Les itérateurs

Principe de l’itérateur
  • Une collection v dont les éléments sont de type T

  • i1 pointe le début de la collection (e.g., obtenu avec v.begin())

  • i2 pointe la fin de la collection (e.g., obtenu avec v.end())

  • *i1 est l'élément de type T pointé par i1

./Images/Jak_Kirman_Iterator.gif
Tip
Itérateurs VS pointeurs
  • Le slogan est itérateur = pointeur (sur les éléments d’un conteneur).

  • Un pointeur normal peut être considéré comme un itérateur (sur un tableau C) !

int myints[]= {10,20,30,40,50};
set<int> s (myints,myints+5);
//on initialise s en considérant le tableau C myints[] comme une collection
Affichage des éléments d’un conteneur
ostream& operator<<(ostream& out, const data_t& s){
  for(data_t::const_iterator it=s.cbegin(); it != s.cend(); ++it)
    //parcours de l'ensemble s avec un itérateur it
    out << *it;
    //pour chaque élément pointé par it, l'afficher
  return out;
}
  • Dans la boucle for, on déclare un itérateur (constant) data_t::const_iterator it pour parcourir s;

  • On initialise it avec it=s.cbegin() et on avance it tant qu’on a pas atteint la fin de s avec s.cend();

  • Ainsi, on parcoure le contenu d’un conteneur s de type data_t (rappel, défini comme étant un alias pour set<att_t>).

Important La déclaration des opérateurs de sortie << est très particulière. On procède ainsi pour pouvoir écrire cout << f << endl;
Tip
Le mot-clef auto
  • une nouveauté du standard C++11

  • nécessite le paramètre -std=c++11 de g++

  • permet de déterminer automatiquement (inférence) un type, lorsque ce n’est pas ambiguë

  • particulièrement agréable pour les itérateurs !

  for(auto it=s.cbegin(); it != s.cend(); ++it)
    out << *it;

2.2.3. Les algorithmes

  • une collection (fournie) d'algorithmes standards

  • utilise systématiquement les itérateurs

  • le code générique est donné

  • d’excellents exemples sont présentés

Exemple, l’algorithme générique count
template <class InputIterator, class T>
  ptrdiff_t count ( InputIterator first, InputIterator last, const T& value )
{
  ptrdiff_t ret=0;
  while (first != last)
    if (*first++ == value)
      ++ret;
  return ret;
}

  cout << "count(sigma.begin(),sigma.end(),f) = " << count(sigma.begin(),sigma.end(),f) << endl;
  //compte génériquement (et linéairement !) le nombre d'occurrences de f dans sigma
Important Attention toutefois à la complexité des algorithmes génériques : une recherche générique find(s.begin(), s.end(), x) sur un set<T> s sera linéaire en version générique mais logarithmique avec s.find(x) qui exploite la structure sous-jacente d’arbre rouge et noir utilisée dans l’implémentation de set<T>
La fermeture d’un ensemble d’attributs (voir [algo.LIF10])
data_t closure(const df_set_t &s, const data_t &x){
  data_t r(x);
  //on copie les attributs initiaux dans le résultat
  size_t i;
  //la taille courante de r, pour déterminer si on atteint le point fixe
  do{
    i=r.size();
    for(auto it=s.cbegin() ; it !=s.cend() ; ++it){
    //pour chaque dépendance *it de s
      if(includes(r.cbegin(),r.cend(), it->_src.cbegin(), it->_src.cend()))
        //si cette dépendance est déclenchable, alors on ajoute sa conclusion à r
        r.insert(it->_dst.cbegin(), it->_dst.cend());
    }
  } while(i!=r.size());
  // le point fixe est atteint
  return r;
}
Important
Différences entre spécification formelle en pseudo-code et réalisation en C++
  • l’extrait C++ est une réalisation (naïve) de [algo.LIF10]

  • mais ce qui est dit et un peu différent de ce qui est fait

  • indice : comparer le nombre total de tests d’inclusion

3. Conclusion

Ce qu’il faut retenir
  • l’objectif de ce cours est de vous faciliter les TPs LIF1LC et LIFLF

  • en théorie, il est possible de faire ces TPs en "pur C" :

    • sans objets, sans références, sans namespaces, sans templates

    • utiliser éventuellement la glib http://developer.gnome.org/glib/ pour compléter la librairie standard (du C)

  • pour aller plus loin, dans votre cursus au département informatique :

    • l’UE sur la programmation objet (en Java)*

    • l’UE sur la programmation générique (en C++)*

    • les UEs sur la complexité et la calculabilité*

Important

Pour les TPs LIFLC et LIFLF, ne pas vous avancer trop loin :

  • en programmation objet (sauf si vous êtes déjà à l’aise !)

    • e.g., définir et surcharger des méthodes d’objets et de classes, définir des constructeurs, utiliser typedef dans une classe

  • en programmation générique

    • e.g., rendre tout le code indépendant du choix de la représentation des attributs (ici, en char)

  • dans les arcanes du C++

S’aventurer sur ces points n’est pas l’objet des TPs LIFLC et LIFLF : ce n’est pas nécessaire, c’est difficile, ça vous prendra trop de temps et vous vous tirerez une balle dans le pied !

Le programmé donné en annexe permet de répondre aux questions posées en LIFBDW2
./Images/LIF10-ExerciceDF.png

Appendix A: Code complet

    1: //g++ -Wall -Wextra -std=c++0x -pedantic Simple.cpp -o Simple
    2: #include <iostream>
    3: #include <algorithm>
    4: #include <set>
    5: #include <cstdlib>
    6: #include <sstream>
    7: #include <fstream>
    8:
    9: using namespace std;
   10:
   11: /*********** Ensembles d'attributs ***********/
   12:
   13: const string ARROW_STR="->";
   14:
   15: typedef char att_t;
   16: //pour éviter de trop dépendre du type concret des attributs
   17: typedef set<att_t> data_t;
   18: //un ensemble d'attributs
   19: ostream& operator<<(ostream& out, const data_t& s){
   20:   //affiche un ensemble d'attributs sur la sortie 'out'
   21:   for(data_t::const_iterator it=s.cbegin(); it != s.cend(); ++it)
   22:   //pour chaque attribut (*it) de l'ensemble s
   23:     out << *it;
   24:     // afficher (*it)
   25:   return out;
   26: }
   27:
   28: /*********** Dépendances Fonctionnelles (DF) ***********/
   29:
   30: struct df_t {
   31: //une DF est une paire d'ensembles d'attributs
   32:     data_t _src;
   33:     data_t _dst;
   34: };
   35: bool operator == (const df_t &lhs, const df_t &rhs){
   36:   //pour savoir si des DFs son égales
   37:   return (lhs._src == rhs._src && lhs._dst == rhs._dst);
   38: }
   39: bool operator < (const df_t &lhs, const df_t &rhs){
   40:   //pour comparer des DFs selon l'ordre lexicogrpahique
   41:   //nécessaire pour
   42:   return (lhs._src < rhs._src || (lhs._src == rhs._src && lhs._dst < rhs._dst));
   43: }
   44: ostream& operator<<(ostream& out, const df_t &f){
   45:   //pour afficher des DFs sur la sortie 'out'
   46:   out << f._src << " " << ARROW_STR << " "<< f._dst;
   47:   return out;
   48: }
   49: istream& operator>> (istream& in, df_t& f){
   50:   //A VERIFIER/NON DOCUMENTE
   51:   string str;
   52:   getline(in,str);
   53:   istringstream isstr(str);
   54:   bool src(true);
   55:
   56:   while(isstr.good()){
   57:     isstr >> str;
   58:     if(str.empty() || str[0]=='#')
   59:       break;
   60:     if(str==ARROW_STR)
   61:       src=false;
   62:     else{
   63:       if(src)
   64:         f._src.insert(str.begin(),str.end());
   65:       else
   66:         f._dst.insert(str.begin(),str.end());
   67:     }
   68:   }
   69:   return in;
   70: }
   71:
   72: /*********** Ensembles de DFs ***********/
   73:
   74: typedef set<df_t> df_set_t ;
   75: //un ensemble de dépendances
   76: ostream& operator<<(ostream& out, const df_set_t &s){
   77:   //pour afficher un ensemble de DFs sur la sortie 'out'
   78:   for(auto it=s.cbegin(); it != s.cend(); ++it)
   79:     out << *it << endl;
   80:   return out;
   81: }
   82:
   83: void readDFs(const string &file, df_set_t &s){
   84:   //A VERIFIER/NON DOCUMENTE
   85:   s.clear();
   86:   ifstream myfile (file.c_str(), ios::in);
   87:   df_t f;
   88:   while(myfile.good()){
   89:     f._src.clear(); f._dst.clear();
   90:     myfile >> f;
   91:     if(!f._src.empty() && !f._dst.empty())
   92:       s.insert(f);
   93:   }
   94: }
   95:
   96: /*********** Algorithmes ***********/
   97:
   98: data_t schema(const df_set_t& s){
   99:   // pour calculer la liste de tous les attributs qui apparaissent dans l'ensemble
  100:   // typiquement, cette fonction pourrait être un membre d'une classe pour les df_set_t
  101:   data_t r;
  102:   for(auto it = s.cbegin(); it!=s.cend(); ++it){
  103:   //pour chaque df X -> Y
  104:     r.insert(it->_src.cbegin(),it->_src.cend());
  105:     //on ajoute à r les attributs de X
  106:     r.insert(it->_dst.cbegin(),it->_dst.cend());
  107:     //on ajoute à r les attributs de Y
  108:   }
  109:   return r;
  110: }
  111:
  112: data_t closure(const df_set_t &s, const data_t &x){
  113:   data_t r(x);
  114:   size_t i;
  115:   do{
  116:     i=r.size();
  117:     for(auto it=s.cbegin() ; it !=s.cend() ; ++it){
  118:       if(includes(r.cbegin(),r.cend(), it->_src.cbegin(), it->_src.cend()))
  119:         r.insert(it->_dst.cbegin(), it->_dst.cend());
  120:     }
  121:   } while(i!=r.size());
  122:   return r;
  123: }
  124:
  125: bool models(const df_set_t &s, const df_t &f){
  126:     data_t c = closure(s, f._src);
  127:     return includes(c.cbegin(), c.cend(), f._dst.cbegin(),f._dst.cend());
  128: }
  129:
  130: /*********** main ***********/
  131:
  132: int main (){
  133:   cout << "Dependances : " << endl;
  134:   df_t f, g, h;
  135:     cout << "#01 f : " << f << '.' << endl;
  136:   f._src.insert('C');
  137:     cout << "#02 f : " << f << '.' << endl;
  138:   data_t d = {'D', 'A'};
  139:   f._dst = d;
  140:     cout << "#03 f : " << f << '.' << endl;
  141:
  142:   g._src = {'B', 'B'};
  143:   g._dst = {'A', 'C'};
  144:     cout << "#04 g : " << g << '.' << endl;
  145:
  146:     cout << "#05 f == f : " << (f == f) << endl;
  147:     cout << "#06 f == g : " << (f == g) << endl;
  148:     cout << "#07 f <  g : " << (f < g)  << endl;
  149:     cout << "#08 g <  f : " << (g < f)  << endl<<endl;
  150:
  151:   cout << "Ensemble de dependances : " << endl;
  152:   df_set_t s = {f, g, f};
  153:     cout << "#09 {f,g}'s schema : " << schema(s) << endl;
  154:     cout << "#10 {f,g} : " << endl << s << endl;
  155:
  156:
  157:   cout << "Fermetures : " << endl;
  158:     cout << "#11 A+ : " << closure(s, {'A'})<< endl;
  159:     cout << "#12 B+ : " << closure(s, {'B'})<< endl << endl ;
  160:
  161:   cout << "Implications : " << endl;
  162:   h._src = {'A'};
  163:   h._dst = {'A'};
  164:     cout << "#13 {} |- " << h << " : " << models(df_set_t(),h)<< endl;
  165:   h._src = {'A'};
  166:   h._dst = {'B'};
  167:     cout << "#14 {} |- " << h << " : " << models(df_set_t(),h)<< endl;
  168:   h._src = {'B'};
  169:   h._dst = {'D'};
  170:     cout << "#15 {f,g} |- " << h << " : " << models(s,h)<< endl << endl;
  171:
  172:   readDFs("./example.txt",s);
  173:     cout << "#16 lecture de \"./example.txt\" dans {...} : "<< endl << s << endl;
  174:   h._src = {'A', 'E'};
  175:   h._dst = {'D'};
  176:     cout << "#17 {...} |- " << h << " : " << models(s,h)<< endl;
  177:
  178:   return EXIT_SUCCESS;
  179: }

Appendix B: Résultat de l’exécution

g++ -Wall -Wextra -std=c++0x -pedantic Simple.cpp -o Simple && ./Simple (g++ 4.6.3)
Dependances :
#01 f :  -> .
#02 f : C -> .
#03 f : C -> AD.
#04 g : B -> AC.
#05 f == f : 1
#06 f == g : 0
#07 f <  g : 0
#08 g <  f : 1

Ensemble de dependances :
#09 {f,g}'s schema : ABCD
#10 {f,g} :
B -> AC
C -> AD

Fermetures :
#11 A+ : A
#12 B+ : ABCD

Implications :
#13 {} |- A -> A : 1
#14 {} |- A -> B : 0
#15 {f,g} |- B -> D : 1

#16 lecture de "./example.txt" dans {...} :

#17 {...} |- AE -> D : 0

Appendix C: Types d’itérateurs

Important
Les variantes des itérateurs dans la STL

Les conteneurs ne permettent pas tous les mêmes opérations avec les itérateurs selon :

  • que l’on ne fasse qu'avancer (ForwardIterator) (tous les conteneurs proposent ce type d’itérateurs)

  • que l’on puisse reculer (BiDirectionalIterator)

  • que l’on puisse accéder directement à un indice arbitraire (RandomAccessIterator)

    • c’est typique des structures de tableau (e.g., vector<T>)

    • ce n’est pas possible pour set<T> utilisé ici

  • ce que l’on fait des éléments (InputIterator et OutputIterator)

C’est à savoir pour comprendre les messages d’erreur de g++, mais il n’y a pas lieu de (trop) s’en préoccuper.

Appendix D: Gestion de la mémoire en C++

Note
Allocation dynamique manuelle

Quand la l’allocation manuelle est nécessaire (ou très souhaitable) : attention aux changements entre C et C++ !

new pour l’allocation

  char* text;
  text = new char[1000];
  char* one_char = new char;

delete et delete[] pour la suppression

  delete[] text;
  delete one_char;
Important Comme en C, le programmeur est responsable de la gestion de la mémoire, à lui de tout libérer (dans le bon ordre, au bon moment) et de ne pas garder de dangling pointeurs.
Important Surtout ne pas mixer new/delete avec malloc/free : le comportement n’est pas garanti.

Références