La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Structures de données IFT-2000 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009.

Présentations similaires


Présentation au sujet: "Structures de données IFT-2000 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009."— Transcription de la présentation:

1 Structures de données IFT-2000 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009

2 Plan  Introduction  Du C au C++  Les commentaires,  Déclaration des variables  Le type bool  Le qualificatif const  Le type composé struct  Surcharge des fonctions  Fonctions avec arguments par défaut  Les fonctions inline  Les fonctions statiques  Passage d’arguments par référence  Les fonctions génériques  Allocation dynamique de la mémoire  Opérateur de résolution de portée  Les exceptions  L’édition des liens

3 Introduction Cette partie du cours suppose comme pré-requis le langage C.  Quelques vérités la programmation orientée objet n‘est pas le C++ on peut programmer « orienté objet » en C++ on peut programmer « sans objets » en C++

4 Introduction  C date de 1972 son créateur est Dennis Ritchie(Bell Labs) il a été normalisé en 1989 ANSIX3.159 1989  C++ date de 1980 son créateur est Bjarne Stroustrup (Bell Labs) Bjarne Stroustrup définit le successeur de C. Plutôt que D ou P (soit la suite de C dans l’alphabet, ou la suite de C dans BCPL), Stroustrup baptise son bébé C++ (le premier nom donné à ce nouveau langage était “C with classes”.), entendant par là que C++ est «a better C», un C meilleur, incrémenté. Dans l'idée de Stroustrup, C++ devait conserver les idées de base ayant conduit à la réalisation de C (typage statique, efficacité d'exécution, langage compilé). Il est intéressant de constater que UNIX, C et C++ sont tous des bricolages de Laboratoire!

5 Langages C, C++ et UNIX En ce sens, ces trois produits sont à l’opposé de certains produits ayant fait l’objet d’une spécification très poussée. Un langage, aussi bon ou aussi mauvais soit-il, n’a jamais fait la qualité ni le succès d’un programme, comme le démontre nombre de réussites et d’échec industriels. Beaucoup plus que le langage de programmation utilisé, c’est le code déjà écrit et testé qui permet d’optimiser les coûts de production de grands logiciels. Le meilleur langage est celui que l’on connaît, le meilleur code, et le plus rapidement disponible- celui qui tourne déjà sans erreurs. Sur la base de ces hypothèses, C++ apparaît comme un langage très puissant, connu par beaucoup de programmeurs dans le monde, et soutenu par une masse de code existant et disponible probablement à nulle autre pareille.

6 Avantages du langage Ironiquement, les principaux “+” (surcharge d'opérateurs, classes) de C++ sont des caractéristiques introduites dans des langages antérieurs à C lui-même, qui est à l'origine de C++ (Algol-68, Simula-67). On peut se fonder actuellement sur des bibliothèques de logiciels très vastes (communications, protocoles, fenêtrages, algorithmique, traitement d’images, etc...) offrant des interfaces écrites dans un même langage.

7 Du C au C++  Compatibilité avec le langage C. Un compilateur C++ peut compiler un code C écrit selon la norme ANSI C.  Typage fort Le langage C est un langage faiblement typé.Les compilateurs C sont “ laxistes ” et laissent beaucoup (trop) de liberté au programmeur. Le langage C++ introduit un typage fort beaucoup + strict. Les compilateurs font + de vérifications tout en produisant un code aussi efficace.  Références  Surdéfinition des fonctions (surcharges)  Généricité Premier + Deuxième +  Classes et objets  Héritages simple et multiple  Polymorphisme et liaison dynamique

8 Introduction  « hello world » en C++ #include int main(){ printf("hello world\n"); return 0; } #include int main(){ cout << "hello world" << endl; return 0; }

9 Un C amélioré  Les commentaires Trois types de commentaires … type« bloc» type« ligne» type« Doxygen» /* blablabla blablabla */ // blablabla Une« surprise», que fait ceci en C et en C++ ? x = a //* divisons par b */b /** commentaire spécial type Doxygen

10 Un C amélioré  Les constantes L ‘utilisation du préprocesseur C est une source d’erreurs difficiles à détecter. En C++ l ‘utilisation du préprocesseur est réduite à: la compilation conditionnelle et à l ‘inclusion de fichiers #ifdef toto … #endif #include « toto.h

11 Un C amélioré  Les constantes Le préprocesseur n ‘est plus utilisé pour définir des constantes avec des « #define» dans les.h En C++ il y a le mot clé « const » pour définir les constantes. #define K 1024 const int K = 1024; « const » signifie que la donnée définie ne peut être modifiée

12 Un C amélioré  Les constantes Les contrôles concernant les constantes sont faits statiquement à la compilation et le fait que les constantes soient déclarées comme des variables n‘affecte en rien les performances du programme au moment de l‘exécution. Il est donc inutile en C++ (bien que cela soit possible) de conserver des constantes du genre « #define» pour tenter d‘économiser de la place ou accélérer le programme. Il vaut mieux confier ce type d‘optimisations au compilateur.

13 Un C amélioré  Les constantes const int i = 7; const double pi = 3.1416; const char titre[] = "toto"; const int x; i++; titre[3] = ‘ a ’;

14 Un C amélioré  Les pointeurs constants int i = 0; // variable int j; int* const iptr = &i; i=1; //ok *iptr = 2; // ok iptr = &j; // non Pointeur constant sur une variable

15 Un C amélioré  Les pointeurs constants const int n = 0; // constante const int p = 1; // constante int* const nptr = &n; // non const int* const pptr = &p; // ok *pptr = 2; // interdit pptr = &n; // interdit pptr = nptr; // interdit Pointeur constant sur une constante

16 Un C amélioré  Déclarations et définitions de variables const int N = 10; int i; for(i=0; i<N; i++) {…} int deuxN = N *2; for(int j=0; j<deuxN; j++) {…} if (int k = get()) { i=k;} else {j= k; } while (int m = get()) { i += m}; switch (int n = get()) { case 0: i = 1*n; break; case 1: i = 2*n; break; default: i = 3*n; break; } On déclare une variable quand on en a besoin.

17 Un C amélioré  Déclarations et définitions de variables En C++ on peut donc d é clarer les variables ou fonctions n'importe o ù dans le code. La port é e de telles variables va de l'endroit de la d é claration jusqu' à la fin du bloc courant. Exemple #include int main() {int j = 0; for(int w=0; w<10; w++, j++) {int i = w; cout << i << ' '; } int k = j; //permet une initialisation "dynamique" return 0; }

18 Un C amélioré  Déclarations et initialisation des variables Il est possible, en C++ comme en C, d ’ affecter une valeur à une variable au moment de sa d é claration. Il y a cependant 2 syntaxes en C++ pour le faire. Syntaxe classique:int i =2; //comme dans le langage C Syntaxe propre au C++:int i(2); La nouvelle syntaxe de la d é claration-initialisation est: ( ); O ù valeur est n ’ importe quel litt é ral ou expression du type indiqu é. Exemples int i(18); float var(3.1415); char c( ’ a ’ ); int j(i); float x(2.0*var);

19 Un C amélioré  Visibilité des variables L'op é rateur de r é solution de port é e :: permet d'acc é der aux variables globales, interdites, plutôt qu'aux variables locales. Exemple #include int i = 11; int main() { int i = 34; { int i = 23; ::i = ::i + 1; cout << ::i << " " << i << endl; } cout << ::i << " " << i << endl; return 0; }

20 Un C amélioré  Le type bool Le C++ contient un type bool servant à représenter le résultat des opérations logiques. Une variable de type bool ne peut prendre que deux valeurs: true et false. Par exemple: bool b=true; b = 5 < 4; // b vaut false b = 5 + 4; // b vaut true Remarquez qu’une expression arithmétique convertie en un bool vaut true si et seulement si elle s’évalue à une valeur différente de 0. La fonction suivante détermine si un tableau d’entiers est en ordre croissant: bool croissant(int tab[], int n) { for (int i=1; i<n; i++) if (tab[i]<tab[i-1]) return false; return true; }

21 Un C amélioré  Retour sur le qualificatif const Il est utile donc pour définir des constantes symboliques mais aussi pour indiquer que certains objets passés en paramètre de doivent pas être modifiés. Comme on l’a déjà vu, on déclare une constante en ajoutant le mot clef const. const float pi=3.1416; // Cette valeur ne pourra plus être modifiée // par le programme, plus exactement toute tentative de modification // sera rejetée par le compilateur, qui signalera une erreur. const int tab[]={1,2,3,4,5} // tab[i] est une constante int n=0; const int* cp1=&n; // *cp1 ne peut pas être modifié int* const cp2=&n; // cp2 ne peut pas être modifié const int* const cp3=&n // cp3 et *cp3 ne peuvent pas être modifiés

22 Un C amélioré  Retour sur le qualificatif const De façon générale, le mot clef const modifie un type afin de restreindre les possibilités d'utilisation d'un objet. Par exemple on peut exiger qu'une variable dont l'adresse est passée en paramètre ne soit pas modifiée. void f(const int* p) { // *p ne peut pas être modifié } void g(const int t[]) { t[0]=0; // erreur }

23 Un C amélioré  Le type composé struct typedef n'est plus obligatoire pour renommer un type. Exemple struct FICHE { char *nom, *prenom; int age; }; FICHE adherent, *liste;

24 Un C amélioré  Le type composé struct  À la différence en C, on peut en C++ définir des fonctions/méthodes à l’intérieur d’une struct, à l’instar d’une classe.  En effet, le C++ perçoit une struct comme une classe dont les membres sont publiques par défaut.  Nous y reviendrons…

25 Un C amélioré  Surcharge de fonctions Contrairement au langage C, deux fonctions peuvent avoir le même nom, pourvu que leurs signatures soient différentes. On parle alors de surchage de fonctions. La surcharge est un mécanisme qui permet de donner différentes signatures d'arguments à une même fonction. Vous pouvez nommer de la même façon des fonctions de prototypes différents. L'intérêt est de pouvoir nommer de la même manière des fonctions réalisant la même opération à partir de paramètres différents.

26 Un C amélioré  Surcharge de fonctions double add(double a, double b){ return a + b; } int add(int a, int b){ return a + b; } int i = add(1, 2); double d = add(1.0, 2.0); (int, add, int, int) (double, add, double, double) Il est donc permis de définir dans un même programme deux ou Plusieurs fonctions portant le même nom. Cela implique que ces fonctions doivent différer au niveau de leur prototype/signature.

27 Un C amélioré  Surcharge de fonctions Exemple 1 int somme(int arg1, int arg2, int arg3) {// fonction 1 return arg1+arg2+arg3; } int somme(int arg1, int arg2) {// fonction 2 return arg1+arg1; } float somme(float arg1, float arg2) {// fonction 3 return arg1+arg1; } int main { int x1, x2; float y; // appel de la fonction 1 x1 = somme(1,4,2); // appel de la fonction 2 x2 = somme(1,4); // appel de la fonction 3 y = somme(2,4); return 0; }

28 Un C amélioré  Surcharge de fonctions Exemple 2  Attention: le compilateur utilise seulement la liste des paramètres pour distinguer les fonctions de même nom.  Le type de retour n'est pas pris en compte. bool methode1 (int p1, int p2); double methode1 (int p1, int p2); Pour le compilateur, ces deux méthodes sont identiques.

29 Un C amélioré  Surcharge de fonctions Le compilateur s'y retrouve parce que le nom « interne » de la fonction contient la liste des paramètres. À la compilation, en consultant la liste des paramètres effectifs, le compilateur établit quelle est la forme de la fonction à appeler. Il est impossible d'avoir des fonctions qui ne diffèrent que par leur type de retour. En effet, le compilateur ne peut pas les distinguer si on omet de récupérer la valeur retournée. La surcharge doit être utilisée pour implanter des traitements similaires.

30 Un C amélioré  Arguments par défaut Le langage C++ permet de spécifier une valeur par défaut aux arguments de fonctions. De cette manière, quand vous utilisez la fonction, vous n'avez à spécifier ces arguments que lorsque leur valeur diffère du défaut. Les valeurs par défaut ne peuvent être spécifiés que lors de la déclaration de la fonction et ne doivent pas être rappelés lors de définition de la fonction.

31 Un C amélioré  Arguments par défaut double add(double a, double b = 2.0){ return a + b; } double d = add(1.0, 2.0); double dd = add(1.0); Les arguments d’une fonction peuvent donc avoir des valeurs par défaut Pour les paramètres formels de fin. Si, lors d’un appel, les paramètres correspondants ne sont pas spécifiés, alors les valeurs par défaut sont utilisées.

32 Un C amélioré  Arguments par défaut Dans l’exemple de la fonction mult() suivante, on aurait pu obtenir le même résultat en utilisant un argument par défaut: int mult(int x, int y=2) { return x*y } Lors d'un appel à la fonction mult, si le second paramètre est omis alors il est automatiquement remplacé par la valeur 2. Ainsi mult(3) retournera 6 et mult(3,5) retournera 15. Seul les derniers paramètres peuvent avoir une valeur de défaut. Par exemple la définition suivante est invalide. int mult(int x=2, int y) { return x*y; }

33 Un C amélioré  Arguments par défaut Dans le cas d’une fonction avec prototype et définition distincts, la spécification des arguments avec valeur par défaut ne doit être réalisée que lors du prototypage. Exemple void f(int x, int y=2, int z=3); //prototype void f(int x, int y, int z) {... } // définition... f(1) f(1,2,3) f(0,1) f(0,1,3)

34 Un C amélioré  Surcharge de méthodes et arguments par défaut  l'utilisation de la surcharge de méthode peut entrer en conflit avec l'utilisation des paramètres par défaut… int A(); void A(int v1=0, int v2=0); Il y aura conflit entre A() et A(int v1=0, int v2=0).

35 Un C amélioré  Fonctions « inline » Le C++ dispose du mot cl é inline, qui permet de modifier la m é thode d ’ impl é mentation des fonctions. Plac é devant la d é claration d ’ une fonction, il propose au compilateur de ne pas instancier cette fonction. Cela signifie que l ’ on d é sire que le compilateur remplace l ’ appel de la fonction par le code correspondant. Si la fonction est grosse ou si elle est appel é e souvent, le programme devient plus gros, puisque la fonction est r éé crite à chaque fois qu ’ elle est appel é e. En revanche, il devient nettement plus rapide, puisque les m é canismes d ’ appel de fonctions, de passage des param è tres et de la valeur de retour sont ainsi é vit é s. De plus, le compilateur peut effectuer des optimisations additionnelles qu ’ il n ’ aurait pas pu faire si la fonction n ’é tait pas inlin é e. En pratique, on r é servera cette technique pour les petites fonctions appel é es dans du code devant être rapide ( à l ’ int é rieur des boucles par exemple), ou pour les fonctions permettant de lire des valeurs dans des variables.

36 Un C amélioré  Fonctions « inline » Cependant, il faut se méfier. Le mot clé inline est un indice indiquant au compilateur de faire des fonctions inline. Il n’y est pas obligé. La fonction peut donc très bien être implémentée classiquement. Pire, elle peut être implémentée des deux manières, selon les mécanismes d’optimisation du compilateur. De même, le compilateur peut également inliner les fonctions normales afin d’optimiser les performances du programme. De plus, il faut connaître les restrictions des fonctions inline : elles ne peuvent pas être récursives ; elles ne sont pas instanciées, donc on ne peut pas faire de pointeur sur une fonction inline.

37 Un C amélioré  Fonctions « inline » Si l’une de ces deux conditions n’est pas vérifiée pour une fonction, le compilateur l’implémentera classiquement (elle ne sera donc pas inline). Enfin, du fait que les fonctions inline sont insérées telles quelles aux endroits où elles sont appelées, il est nécessaire qu’elles soient complètement définies avant leur appel. Cela signifie que, contrairement aux fonctions classiques, il n’est pas possible de se contenter de les déclarer pour les appeler, et de fournir leur définition dans un fichier séparé. Dans ce cas en effet, le compilateur générerait des références externes sur ces fonctions, et n’insérerait pas leur code. Ces références ne seraient pas résolues à l’édition de lien, car il ne génère également pas les fonctions inline, puisqu’elles sont supposées être insérées sur place lorsqu’on les utilise.

38 Un C amélioré  Fonctions « inline » inline double add(double a, double b){ return a + b; } Il est possible donc de définir des fonctions « en ligne ». Le compilateur, à chaque appel de la fonction mise « en ligne », ne provoque pas un appel classique de fonction mais insère à cet endroit le code de la fonction dans lequel les paramètres formels sont remplacés par les paramètres effectifs. La mise « en ligne » permet d’accélérer l’exécution d’un programme en supprimant l’appel de fonction, le passage des paramètres dans la pile, puis le retour de fonction.

39 Un C amélioré  Fonctions « inline » Autre exemple inline int Max(int i, int j) { if (i>j) return i; else return j; } Pour ce type de fonction, il est tout à fait justifi é d ’ utiliser le mot clé inline.

40 Un C amélioré  Fonctions statiques Par défaut, lorsqu’une fonction est définie dans un fichier C/C++, elle peut être utilisée dans tout autre fichier pourvu qu’elle soit déclarée avant son utilisation. Dans ce cas, la fonction est dite externe. Il peut cependant être intéressant de définir des fonctions locales à un fichier, soit afin de résoudre des conflits de noms (entre deux fonctions de même nom et de même signature mais dans deux fichiers différents), soit parce que la fonction est uniquement d’intérêt local. Le C et le C++ fournissent donc le mot clé static qui, une fois placé devant la définition et les éventuelles déclarations d’une fonction, la rend unique et utilisable uniquement dans ce fichier. À part ce détail, les fonctions statiques s’utilisent exactement comme des fonctions classiques.

41 Un C amélioré  Fonctions statiques Exemple // Déclaration de fonction statique static int locale1(void); // Définition de fonction statique static int locale2(int i, float j) { return i*i+j; }

42 Un C amélioré  Passage d’arguments par référence void add(int a, int b, int &sum) { sum = a + b; } int A, B, SUM; A = 0; B = 1; SUM = 2; cout << SUM << endl; add(A, B, SUM); cout << SUM << endl; En C++, on peut passer par référence sans avoir à manipuler l’adresse explicitement en utilisant un synonyme d’une variable. Cette syntaxe indique que sum va être le synonyme du paramètre actuel qui sera utilisé lors de l’appel: Sum partagera alors la même mémoire que le paramètre actuel.

43 Un C amélioré  Fonctions génériques La générécité est le fait que el code d’une fonction soit indépendant du type des objets qu’elle manipule. template fonction template inline T add (T a, T b){ return a+b; } Avec T = int, ça donne inline T add (T a, T b){ return a+b; }

44 Un C amélioré  Fonctions génériques template inline T max (T x, T y){ return (x>y ? x:y); } template T max (T t[], int sz){ T mx = t[0]; for(int i = 1; i < sz; i++) mx = max (mx, t[i]); return mx; } int tab_int[] = {2, 4, 8, 16, 1, 5, 9, 17}; float tab_float [] = {1.0, 3.3, 4.4, 2.2, 10.10, 1.3}; cout (tab_int, int (sizeof(tab_int)/sizeof(int))); cout (tab_float, int (sizeof(tab_float)/sizeof(float)));

45 Un C amélioré  Fonctions génériques max(1,2); est équivalent à Max (1,2); On peut aussi appeler explicitement les types du template lors de l’appel de la fonction.

46 Un C amélioré  Fonctions génériques Exercice. Avec les templates, reinterpret_cast et le passage de paramètres Par référence, écrivez une fonction générique qui recopie octet par octet le contenu d’un opérande dans un autre (une sorte de strcpy() en C++). Solution. template void memcpy(TS src, TD &dst) { int sz = sizeof(src); if( sz > sizeof(dst)) sz = sizeof(dst); char *src2 = reinterpret_cast (&src); char *dst2 = reinterpret_cast (&dst); for (int i=0; i < sz; i++) dst[i] = src[i]; }

47 Un C amélioré  Fonctions génériques Exercice. Réutilisez la fonction memcpy() dans une nouvelle fonction tabcpy() dont le but est de copier un tableau dans un autre de même taille. Solution. template void tabcpy(E *src, E *dst, int n) { for (int i=0; i < n; i++) memcpy (src[i], dst[i] ); }

48 Un C amélioré  Allocation dynamique L’allocation dynamique fait partie intégrante du C++. Ce ne sont plus des Fonctions qu’il faut savoir utiliser comme malloc(), realloc, fre()… Deux opérateurs sont prévus: new et delete. struct Toto { int i; float f; }; typedef Toto* TotoPtr; TotoPtr t = new Toto; // équivalent à (TotoPtr) malloc(sizeof(structToto)).... t->i = 1; t->f = 1.0; delete t; // équivalent à free(t);

49 Un C amélioré  Allocation dynamique L’allocation des tableaux est quasiment identique. Deux opérateurs sont prévus: new [] et delete []. struct Toto { int i; float f; }; typedef Toto* TotoPtr; TotoPtr t = new Toto[10];... t[0].i = 1; t[0].f = 1.0; delete [] t;

50 Un C amélioré  Allocation dynamique L’opérateur new[] permet également d’allouer des tableaux à plusieurs dimensions. Pour cela, il suffit de spécifier les tailles des différentes dimensions à la suite du type de donnée des éléments du tableau, exactement comme lorsque l’on crée un tableau statiquement. Toutefois, seule la première dimension du tableau peut être variable, et les dimensions deux et suivantes doivent avoir une taille entière positive et constante. Par exemple, seule la deuxième ligne de l’exemple qui suit est une allocation dynamique de tableau valide : int i=5, j=3; int (*pi1)[3] = new int[i][3]; // Alloue un tableau de i lignes de trois entiers. int (*pi2)[3] = new int[i][j]; // Illégal, j n’est pas constant. Si l’on désire réellement avoir des tableaux dont plusieurs dimensions sont de taille variable, on devra allouer un tableau de pointeurs et, pour chaque ligne de ce tableau, allouer un autre tableau à la main (dans une boucle).

51 Un C amélioré  Allocation dynamique Attention, il ne faut pas mélanger new/delete avec malloc/free. Il ne faut pas mélanger non plus new/delete et new []/delete []. Sinon, le comportement du programme n’est plus garanti. Il est important donc d’utiliser l’opérateur delete[] avec les pointeurs renvoyés par l’opérateur new[] et l’opérateur delete avec les pointeurs renvoyés par new. De plus, on ne devra pas non plus mélanger les mécanismes d’allocation mémoire du C et du C++ (utiliser delete sur un pointeur renvoyé par malloc par exemple). En effet, le compilateur peut allouer une quantité de mémoire supérieure à celle demandée par le programme afin de stocker des données qui lui permettent de gérer la mémoire. Ces données peuvent être interprétées différemment pour chacune des méthodes d’allocation, si bien qu’une utilisation erronée peut entraîner soit la perte des blocs de mémoire, soit une erreur, soit un plantage.

52 Un C amélioré  Allocation dynamique L’opérateur new[] alloue la mémoire et crée les objets dans l’ordre croissant des adresses. Inversement, l’opérateur delete[] détruit les objets du tableau dans l’ordre décroissant des adresses avant de libérer la mémoire. La manière dont les objets sont construits et détruits par les opérateurs new et new[] dépend de leur nature. S’il s’agit de types de base du langage ou de structures simples, aucune initialisation particulière n’est faite. La valeur des objets ainsi créés est donc indéfinie, et il faudra réaliser l’initialisation soi-même. Si, en revanche, les objets créés sont des instances de classes C++, le constructeur de ces classes sera automatiquement appelé lors de leur initialisation. C’est pour cette raison que l’on devra, de manière générale, préférer les opérateurs C++ d’allocation et de désallocation de la mémoire aux fonctions malloc et free du C. Ces opérateurs ont de plus l’avantage de permettre un meilleur contrôle des types de données et d’éviter un transtypage. Les notions de classe et de constructeur seront présentées en détail dans le chapitre traitant de la couche objet du C++.

53 Un C amélioré  Allocation dynamique Lorsqu’il n’y a pas assez de mémoire disponible, les opérateurs new et new[] peuvent se comporter de deux manières selon l’implémentation. Le comportement le plus répandu est de renvoyer un pointeur nul. Cependant, la norme C++ indique un comportement différent : si l’opérateur new manque de mémoire, il doit appeler un gestionnaire d’erreur. Ce gestionnaire ne prend aucun paramètre et ne renvoie rien. Selon le comportement de ce gestionnaire d’erreur, plusieurs actions peuvent être faites :  soit ce gestionnaire peut corriger l’erreur d’allocation et rendre la main à l’opérateur new ( le programme n’est donc pas terminé), qui effectue une nouvelle tentative pour allouer la mémoire demandée ;  soit il ne peut rien faire. Dans ce cas, il peut mettre fin à l’exécution du programme ou lancer une exception std::bad_alloc, qui remonte alors jusqu’à la fonction appelant l’opérateur new. C’est le comportement du gestionnaire installé par défaut dans les implémentations conformes à la norme.

54 Un C amélioré  Allocation dynamique L’opérateur new est donc susceptible de lancer une exception std::bad_alloc. Voir la partie qui traite de la gestion des exceptions pour plus de détails à ce sujet. Il est possible de remplacer le gestionnaire d’erreur appelé par l’opérateur new à l’aide de la fonction std::set_new_handler, déclarée dans le fichier d’en-tête new. Cette fonction attend en paramètre un pointeur sur une fonction qui ne prend aucun paramètre et ne renvoie rien. Elle renvoie l’adresse du gestionnaire d’erreur précédent.

55 Un C amélioré  Allocation dynamique La fonction std::set_new_handler et la classe std::bad_alloc font partie de la bibliothèque standard C++. Comme leurs noms l’indiquent, ils sont déclarés dans l’espace de nommage std::, qui est réservé pour les fonctions et les classes de la bibliothèque standard. Si vous ne désirez pas utiliser les mécanismes des espaces de nommage, vous devrez inclure le fichier d’en-tête new.h au lieu de new. Attendez vous à ce qu’un jour, tous les compilateurs C++ lancent une exception en cas de manque de mémoire lors de l’appel à l’opérateur new, car c’est ce qu’impose la norme. Si vous ne désirez pas avoir à gérer les exceptions dans votre programme et continuer à recevoir un pointeur nul en cas de manque de mémoire, vous pouvez fournir un deuxième paramètre de type std::nothrow_t à l’opérateur new. La bibliothèque standard définit l’objet constant std::nothrow à cet usage.

56 Un C amélioré  Allocation dynamique Les opérateurs delete et delete[] peuvent parfaitement être appelés avec un pointeur nul en paramètre. Dans ce cas, ils ne font rien et redonnent la main immédiatement à l’appelant. Il n’est donc pas nécessaire de tester la non nullité des pointeurs sur les objets que l’on désire détruire avant d’appeler les opérateurs delete et delete[].

57 Un C amélioré  L’opérateur de résolution de portée « :: » Permet d’accéder à des identificateurs globaux qui seraient masqués par des identificateurs locaux. int i; int f() { int i; i = ::i; } i local i gobal

58 Un C amélioré  Les exceptions Une fonction en face d’un problème qu’elle ne sait pas résoudre lance (throw) Une exception en espérant qu’une fonction appelante à un niveau supérieur Puisse l’intercepter (catch). Cas archi-classique de la division par 0 : le problème. int div(int n, int d) { return n/d; }

59 Un C amélioré  Les exceptions Cas archi-classique de la division par 0 : la solution en C++. int div(int n, int d) { if (d==0) throw 1; // on « lance » en entier… return n/d; } Nous verrons que nous pouvons « lancer » par le biais de throw des objets autre qu’un entier.

60 Un C amélioré  Les exceptions Cas archi-classique de la division par 0 : sa mise en œuvre. int main() { int x(10), y(5); try { x = div(x,y); cout << "Ok" << endl; } catch(int){ cout << "Erreur" << endl; } return 0; };

61 Un C amélioré  Les exceptions Nous reviendrons plus longuement sur la gestion des exceptions car c’est une notion que nous utiliserons très largement dans notre cours.

62 Un C amélioré  L’édition des liens La gestion des symboles concernant les noms ne se fait absolument plus comme en C! En C, à toute fonction toto() correspond un symbole _toto qui permet de linker un programme appelant avec une bibliothèque contenant le code(et donc Le symbole _toto) de la fonction toto(). En C++, à cause du concept de surdéfinition de fonction, cela n ‘est plus possible. En effet, comment différencier à l‘aide du symbole _add les deux fonctions add(int, int) et add(float, float) ?

63 Un C amélioré  L’édition des liens Le C++ crée donc des symboles spéciaux qui représentent la signature des fonctions au lieu des noms de fonctions. Cela s ‘appelle le name « mangling». L ‘opération inverse, passer du nom de la signature au nom de la fonction s ‘appelle le name « demangling». Chaque compilateur peut avoir sa propre convention du mangling/demangling. On ne peut pas toujours linker un code compilé avec un compilateur C++ avec un code compilé avec un autre compilateur C++ sur une même machine. On ne peut debugguer un code C++ que si le debugger C++ sait faire le demangling inverse du compilateur utilisé pour fabriquer le code de l’application. Il est impossible de linker simplement du C++ avec du C ou l’inverse.

64 Un C amélioré  L’édition des liens Conscients de ces problèmes, les concepteurs du C++ ont prévu l’outillage permettant d’interfacer simplement du C++ avec du C. extern "C" { int add_int_C(int, int); float add_float_C(float, float); } int i = add_int_C(1, 2); float f = add_float_C(1.0, 2.0); Le code de add_int_C et add_float_C se trouve dans un fichier C. Header C++ Fichier C++

65 Un C amélioré  Résumé des différences entre le C et le C++ - commentaires // -nouveaux mots réservés -les caractères sont vraiment des char, plus des int -une chaîne de caractères est un tableau de « const char » -la structure définit aussi le type de même nom -un idf const et pas extern ne peut être utilisé ailleurs -on ne peut convertir un void* vers un pointeur sans cast -seuls les pointeurs sur des non const et non volatile peuvent être convertis implicitement vers des void* -déclaration implicite de fonctions est interdite -fonctions avec type de retour nécessite return -extern et static sont réserves à des objets ou des fonctions -toute constante doit être initialisée -pas de type implicite int -on ne mélange pas les enum entre eux ni avec des int


Télécharger ppt "Structures de données IFT-2000 Abder Alikacem Introduction au langage C++ Département d’informatique et de génie logiciel Édition Septembre 2009."

Présentations similaires


Annonces Google