Comme on voit bien dans le programme en bas la cr=E9ation est appell=E9e
plusieurs fois.
Et voil=E0 la sortie du programme :
$ ./a.exe
Declaration m1
--- Constructor called ---
Declaration m1
--- Constructor called ---
Declaration mSum1
--- Constructor called ---
mSum1 =3D m1 + m2
--- Operator "+" called ---
--- Constructor called ---
--- Operator "=3D" called ---
--- Destructor called ---
Declaration mSum2 =3D m1 + m2
--- Operator "+" called ---
--- Constructor called ---
Declaration mSum3
--- Constructor called ---
--- Operator "+" called ---
--- Constructor called ---
--- Operator "=3D" called ---
--- Destructor called ---
Declaration m4 =3D mSum3
--- Copy constructor called ---
0
--- Destructor called ---
--- Destructor called ---
--- Destructor called ---
--- Destructor called ---
--- Destructor called ---
--- Destructor called ---
Ce que m'int=E9resse le plus c'est pourquoi j'ai ces lignes l=E0 :
Declaration mSum2 =3D m1 + m2
--- Operator "+" called ---
--- Constructor called ---
Je ne vois pas l'operator=3D ni de constructeur de copie. Si je mets le
vrai code pour la classe matrix, le mSum2 est en effet la somme des 2,
l'objet est cr=E9=E9 et vit bien =E7a vie...
Quelqu'un saurait-il m'expliquer la suite des appels ici ? J'imagine
que la ligne
--- Constructor called ---
correspond =E0 la cr=E9ation de l'objet temporaire dans l'operator +. Mais
o=F9 est la trace de l'operator =3D ?
Tu utilises STL en disant - voilà fastoche ! Tu n'as pas assisté aux cours tu arrives à la fin du trimestre et dit que tu sais tout faire. C'est vite vérifié... Faut pas etre idiot pour comprendre que c'est pas toi qui as fait le programme
Ouais, sauf qu'on ne parle pas de fonctionnalités avancés mais des structures de base. Les premiers cours d'un langage, ce sont généralement les types de données et les tableaux. Un tableau, en c++ contemporain, c'est un vector.
Faire une matrice en C++ est un peu comme le programme "Hello World". C'est incroyable le nombre de personnes qui l'ont fait pour apprendre le C++.
C'est vrai qu'a partir du moment ou tu as fait une matrice, tu a vu les bases: template sur les données, constructeur, destructeur, overload d'opérateur, interface public, données privées ou protégées, spécialization pour la multiplication avec un scalaire ...
Michael
"Alex Paris" <rbbt.fr@gmail.com> a écrit dans le message de news:
1186580625.416993.284270@57g2000hsv.googlegroups.com...
Tu utilises STL en disant - voilà fastoche ! Tu n'as pas assisté aux
cours tu arrives à la fin du trimestre et dit que tu sais tout faire.
C'est vite vérifié... Faut pas etre idiot pour comprendre que c'est
pas toi qui as fait le programme
Ouais, sauf qu'on ne parle pas de fonctionnalités avancés mais des
structures de base. Les premiers cours d'un langage, ce sont généralement
les types de données et les tableaux. Un tableau, en c++ contemporain, c'est
un vector.
Faire une matrice en C++ est un peu comme le programme "Hello World".
C'est incroyable le nombre de personnes qui l'ont fait pour apprendre le
C++.
C'est vrai qu'a partir du moment ou tu as fait une matrice, tu a vu les
bases: template sur les données, constructeur, destructeur, overload
d'opérateur, interface public, données privées ou protégées,
spécialization pour la multiplication avec un scalaire ...
Tu utilises STL en disant - voilà fastoche ! Tu n'as pas assisté aux cours tu arrives à la fin du trimestre et dit que tu sais tout faire. C'est vite vérifié... Faut pas etre idiot pour comprendre que c'est pas toi qui as fait le programme
Ouais, sauf qu'on ne parle pas de fonctionnalités avancés mais des structures de base. Les premiers cours d'un langage, ce sont généralement les types de données et les tableaux. Un tableau, en c++ contemporain, c'est un vector.
Faire une matrice en C++ est un peu comme le programme "Hello World". C'est incroyable le nombre de personnes qui l'ont fait pour apprendre le C++.
C'est vrai qu'a partir du moment ou tu as fait une matrice, tu a vu les bases: template sur les données, constructeur, destructeur, overload d'opérateur, interface public, données privées ou protégées, spécialization pour la multiplication avec un scalaire ...
Michael
Alex Paris
On 8 août, 16:08, Michael DOUBEZ wrote:
Parler de langage a l'état pur fait penser à un clivage langage de programmation/langage machine. Un langage de programmation utilise des sortes de librairies: des mécanismes comme les exceptions ou les vtables dépendent du compilateur par exemple.
Michael
Je suis désolé, la réponse est déjà faite plus haut. J'ai déj à TOUT compris pour ma question de départ.
alors : en ce qui concerne les librairies malgré le fait que c'était moi même qui a utilisé ce "terme" le premier veuillez consulter la réponse de Fabien LE LEZ : c'est un magasin qui vend des livres. Voilà.
Si on veut bien de la démagogie on peut poursuivre cette discussion en parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la sécheresse, disparition des espèces animales porotégées ou le rechauffement global ? Qu'est-ce que vous en pensez ? Eh oui, si on utilise STL on aura le solei enfin ? non ?
On 8 août, 16:08, Michael DOUBEZ <michael.dou...@free.fr> wrote:
Parler de langage a l'état pur fait penser à un clivage langage de
programmation/langage machine. Un langage de programmation utilise des
sortes de librairies: des mécanismes comme les exceptions ou les vtables
dépendent du compilateur par exemple.
Michael
Je suis désolé, la réponse est déjà faite plus haut. J'ai déj à TOUT
compris pour ma question de départ.
alors : en ce qui concerne les librairies malgré le fait que c'était
moi même qui a utilisé ce "terme" le premier veuillez consulter la
réponse de Fabien LE LEZ : c'est un magasin qui vend des livres.
Voilà.
Si on veut bien de la démagogie on peut poursuivre cette discussion en
parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi
ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la
sécheresse, disparition des espèces animales porotégées ou le
rechauffement global ? Qu'est-ce que vous en pensez ?
Eh oui, si on utilise STL on aura le solei enfin ? non ?
Parler de langage a l'état pur fait penser à un clivage langage de programmation/langage machine. Un langage de programmation utilise des sortes de librairies: des mécanismes comme les exceptions ou les vtables dépendent du compilateur par exemple.
Michael
Je suis désolé, la réponse est déjà faite plus haut. J'ai déj à TOUT compris pour ma question de départ.
alors : en ce qui concerne les librairies malgré le fait que c'était moi même qui a utilisé ce "terme" le premier veuillez consulter la réponse de Fabien LE LEZ : c'est un magasin qui vend des livres. Voilà.
Si on veut bien de la démagogie on peut poursuivre cette discussion en parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la sécheresse, disparition des espèces animales porotégées ou le rechauffement global ? Qu'est-ce que vous en pensez ? Eh oui, si on utilise STL on aura le solei enfin ? non ?
Alex Paris
On 8 août, 16:11, Fabien LE LEZ wrote:
Exercice dont l'énoncé n'a pas été reproduit ici. Si tu as besoin d'un tableau dans un programme, la méthode normale est d'utiliser std::vector<>, sauf si ce n'est pas possible -- soit parce que son interface ne convient pas, soit parce qu'il est explicitement demandé de ne pas l'utiliser.
Si le but de l'exercice est d'implémenter soi-même, dans le détail, un équivalent à std::vector<>, pourquoi pas.
Si le cours est basé sur l'idée qu'implémenter soi-même ce genre de détails (i.e. des new[] partout) est normal/courant, alors c'est un cours de C.
Ecoutez, pour cette fois-ci c'était Jean-Marc Bourguet qui a répondu a ma question. Vous êtes AUSSI intélligent sans nul doute, alors inutile de parler des choses évidentes en passant cela pour la réponse de la question d'origine. Pourquoi le constructeur de copie n'est pas appelé ? NON ! Ce n'est pas parce que je n'ai pas utilisé vector pour la présentantion des données.
On 8 août, 16:11, Fabien LE LEZ <grams...@gramster.com> wrote:
Exercice dont l'énoncé n'a pas été reproduit ici.
Si tu as besoin d'un tableau dans un programme, la méthode normale est
d'utiliser std::vector<>, sauf si ce n'est pas possible -- soit parce
que son interface ne convient pas, soit parce qu'il est explicitement
demandé de ne pas l'utiliser.
Si le but de l'exercice est d'implémenter soi-même, dans le détail, un
équivalent à std::vector<>, pourquoi pas.
Si le cours est basé sur l'idée qu'implémenter soi-même ce genre de
détails (i.e. des new[] partout) est normal/courant, alors c'est un
cours de C.
Ecoutez, pour cette fois-ci c'était Jean-Marc Bourguet qui a répondu a
ma question.
Vous êtes AUSSI intélligent sans nul doute, alors inutile de parler
des choses évidentes en passant cela pour la réponse de la question
d'origine. Pourquoi le constructeur de copie n'est pas appelé ? NON !
Ce n'est pas parce que je n'ai pas utilisé vector pour la
présentantion des données.
Exercice dont l'énoncé n'a pas été reproduit ici. Si tu as besoin d'un tableau dans un programme, la méthode normale est d'utiliser std::vector<>, sauf si ce n'est pas possible -- soit parce que son interface ne convient pas, soit parce qu'il est explicitement demandé de ne pas l'utiliser.
Si le but de l'exercice est d'implémenter soi-même, dans le détail, un équivalent à std::vector<>, pourquoi pas.
Si le cours est basé sur l'idée qu'implémenter soi-même ce genre de détails (i.e. des new[] partout) est normal/courant, alors c'est un cours de C.
Ecoutez, pour cette fois-ci c'était Jean-Marc Bourguet qui a répondu a ma question. Vous êtes AUSSI intélligent sans nul doute, alors inutile de parler des choses évidentes en passant cela pour la réponse de la question d'origine. Pourquoi le constructeur de copie n'est pas appelé ? NON ! Ce n'est pas parce que je n'ai pas utilisé vector pour la présentantion des données.
Loïc Joly
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on parle de C++ ?
Dans le cadre de l'apprentissage, la STL me semble indispensable dans le sens où elle permet une courbe d'apprentissage progressif, qui peut apprendre les choses de base (une boucle, par exemple) avant d'apprendre les choses complexes (la gestion de la mémoire, les constructeurs par copie et autres fonctions nécessaires lorsqu'on gère la mémoire manuellement).
Je ne conçois pas un cours où je parlerai de new ou même de class avant de parler de string et de vector.
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui gère ... (patati patata... regarde plus haut)... d'après moi il n'est pas question de montrer tes connaissance en STL.
Si le prof a demandé un exercice mettant en oeuvre la gestion manuelle de la mémoire, probablement pas. Si c'est un exercice sur la surcharge d'opérateurs et l'écriture d'algorithmes mathématiques, pourquoi s'encombrer l'esprit. Et même dans le premier cas, séparer gestion mémoire du reste en faisant une mini classe vector personnalisée ne me semble pas une mauvaise idée.
Tu pouvais sinon d'aller cherche les lib motif pour faire une belle fenêtre, des ascenseurs, les couleurs : )))) etc. Envoyer les resultats direct sur le mail de prof via un librairie SMTP etc etc. Mais ce n'est pas le but c'est tout
Et pourquoi pas ? Apprendre à utiliser une bibliothèque existante fait partie des compétences qu'un développeur doit maîtriser.
-- Loïc
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on
parle de C++ ?
Dans le cadre de l'apprentissage, la STL me semble indispensable dans le
sens où elle permet une courbe d'apprentissage progressif, qui peut
apprendre les choses de base (une boucle, par exemple) avant d'apprendre
les choses complexes (la gestion de la mémoire, les constructeurs par
copie et autres fonctions nécessaires lorsqu'on gère la mémoire
manuellement).
Je ne conçois pas un cours où je parlerai de new ou même de class avant
de parler de string et de vector.
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui
gère ... (patati patata... regarde plus haut)... d'après moi il n'est
pas question de montrer tes connaissance en STL.
Si le prof a demandé un exercice mettant en oeuvre la gestion manuelle
de la mémoire, probablement pas. Si c'est un exercice sur la surcharge
d'opérateurs et l'écriture d'algorithmes mathématiques, pourquoi
s'encombrer l'esprit. Et même dans le premier cas, séparer gestion
mémoire du reste en faisant une mini classe vector personnalisée ne me
semble pas une mauvaise idée.
Tu pouvais sinon d'aller cherche les lib motif pour faire une belle
fenêtre, des ascenseurs, les couleurs : )))) etc. Envoyer les
resultats direct sur le mail de prof via un librairie SMTP etc etc.
Mais ce n'est pas le but c'est tout
Et pourquoi pas ? Apprendre à utiliser une bibliothèque existante fait
partie des compétences qu'un développeur doit maîtriser.
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on parle de C++ ?
Dans le cadre de l'apprentissage, la STL me semble indispensable dans le sens où elle permet une courbe d'apprentissage progressif, qui peut apprendre les choses de base (une boucle, par exemple) avant d'apprendre les choses complexes (la gestion de la mémoire, les constructeurs par copie et autres fonctions nécessaires lorsqu'on gère la mémoire manuellement).
Je ne conçois pas un cours où je parlerai de new ou même de class avant de parler de string et de vector.
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui gère ... (patati patata... regarde plus haut)... d'après moi il n'est pas question de montrer tes connaissance en STL.
Si le prof a demandé un exercice mettant en oeuvre la gestion manuelle de la mémoire, probablement pas. Si c'est un exercice sur la surcharge d'opérateurs et l'écriture d'algorithmes mathématiques, pourquoi s'encombrer l'esprit. Et même dans le premier cas, séparer gestion mémoire du reste en faisant une mini classe vector personnalisée ne me semble pas une mauvaise idée.
Tu pouvais sinon d'aller cherche les lib motif pour faire une belle fenêtre, des ascenseurs, les couleurs : )))) etc. Envoyer les resultats direct sur le mail de prof via un librairie SMTP etc etc. Mais ce n'est pas le but c'est tout
Et pourquoi pas ? Apprendre à utiliser une bibliothèque existante fait partie des compétences qu'un développeur doit maîtriser.
-- Loïc
Christophe Lephay
"Alex Paris" a écrit dans le message de news:
Si on veut bien de la démagogie on peut poursuivre cette discussion en parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la sécheresse, disparition des espèces animales porotégées ou le rechauffement global ? Qu'est-ce que vous en pensez ? Eh oui, si on utilise STL on aura le solei enfin ? non ?
La démagogie consisterait à tenter de faire croire à un débutant qu'il connait mieux son sujet qu'un expert.
"Alex Paris" <rbbt.fr@gmail.com> a écrit dans le message de news:
1186586429.018138.176490@57g2000hsv.googlegroups.com...
Si on veut bien de la démagogie on peut poursuivre cette discussion en
parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi
ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la
sécheresse, disparition des espèces animales porotégées ou le
rechauffement global ? Qu'est-ce que vous en pensez ?
Eh oui, si on utilise STL on aura le solei enfin ? non ?
La démagogie consisterait à tenter de faire croire à un débutant qu'il
connait mieux son sujet qu'un expert.
Si on veut bien de la démagogie on peut poursuivre cette discussion en parlant de plein choses qui n'ont rien à voir avec le sujet. Pourquoi ne fait-il pas beau ces derniers temps à Paris ? C'est à cause de la sécheresse, disparition des espèces animales porotégées ou le rechauffement global ? Qu'est-ce que vous en pensez ? Eh oui, si on utilise STL on aura le solei enfin ? non ?
La démagogie consisterait à tenter de faire croire à un débutant qu'il connait mieux son sujet qu'un expert.
James Kanze
On Aug 8, 1:27 pm, Michael DOUBEZ wrote:
"Alex Paris" a écrit dans le message de news:
1. Il faut que tu implémentes une classe qui va te SERVIR pour la gestion de matrices... analyse algèbre matricielle etc etc.... 2. Il faut écrire une classe Matrix , template, avec un constructeur de copie, destructor et opérateur =, implémenter les opération s de +, - et * pour cette classe et montrer son utilisation pour le int ! (cours d'informatique à l'école)
Alors on peut avoir des longs débats sur comment rendre les matrices etc super performantes et tout et tout... tandis que le problème n'e st pas là : ) C'est pour avoir la NOTE !
La problématique est la même : pour augmenter tes chances d'avoir u ne bonne note, il faut limiter le risque de faire des erreurs.
Du coup, tu aurais plutot interet à utiliser vector< vector< int > > plutot qu'un int **.
Un vector de vector est la meilleur façon de tout planter. Par exemple si un vecteur s'amuse à lancer une exception pendant un changement de taille, je ne te parle pas de l'état de la matrice.
C'est certainement pas la solution que j'adopterais, non plus. En revanche, je ne crois pas que les exceptions soient un problème. Quoiqu'il arrive, on a une garantie faible sur les données (c'est même un des avantages non négligible des std::vector) ; on est sûr de pouvoir detruire l'objet, et de faire le menage. Et franchement, garantir plus pourrait être très cher si on compte changer les dimensions dynamiquement.
[...]
La méthode classique pour la représentation d'une matrice dense sans autres caractéristiques (triangulaire, diagonale, creuse ...) est d'utiliser un tableau unidimensionnel et d'utiliser operator()(int i, int j){return (i*N+j);} pour acceder aux éléments.
Pour l'utilisation d'un tableau unidimensionnel, je suis tout à fait d'accord. À mon avis, la seule question qui se pose, c'est entre std::vector<T> et T*, avec allocation par appelle à la fonction ::operator new (ou malloc(), mais pas utilisation de l'opérateur new). Le dernier pourrait être intéressant dans certains cas d'utilisation, à condition de bien savoir ce qu'on fait. (Je le déconseillerais fort dans un projet d'école, en revanche.)
En revanche, il y a bien deux écoles en ce qui concerne l'interface. Ce que tu suggères suit Barton et Nackman, mais d'autres ne sont pas de cet avis, et préfère définir l'operator[] pour renvoyer un proxy, sur lequel l'operator[] est également défini, ce qui permet l'écriture m[i][j]. (Je crois que cette deuxième école est plus répandue. Et pour un projet d'école, je me renseignerais sur l'école à laquelle adhère le prof, et j'utiliserai celle-là. Ou j'implémenterais les deux, avec des commentaires qui en expliquent les avantages et les désavantages de chacun.)
A moins que ce ne soit demander (ou que le prof demande l'utilisation de POD comme un tableau de valeurs), l'operateur de recopie n'est pas nécessaire car tout est géré par le compilateur. Et c'est bien de montrer qu'on sait ça aussi.
Pour une matrice, je ne sais pas. Pour commencer, je crois que j'écrirais bien un constructeur de copie moi-même. Ne serait-ce que pour empécher qu'il soit inline, et pour pouvoir l'instrumenter à mon grè par la suite. Mais je m'arrangerais surtout d'utiliser des proxy, de façon à ce que les copies soient rarissimes. (Donc, par exemple, l'operator+ ne renverra pas une matrice, mais seulement un proxy, qui pourrait servir de construire une matrice, ou comme opérand d'un autre opérateur.)
Finalement, les opérateurs algébriques ont intérêt à être définis en dehors de la classe.
Ça dépend, ça aussi. Au moins d'avoir des conversions implicites, ça dépend de l'implémentation.
Il faut dire que des choses comme Matrix sont assez spéciales. Elles servent surtout dans le calcul numérique, où on a assez regulièrement des problèmes de vitesse. Alors, il faut prévoir dès le départ la possibilité d'une phase d'optimisation. C-à-d donc une encapsulation au maximum, pour qu'on peut changer tout en travers s'il faut, sans modifier le code utilisateur. S'il n'est pas question des conversions implicites, mettre les opérateurs dans la classe améliore l'encapsulation.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
On Aug 8, 1:27 pm, Michael DOUBEZ <michael.dou...@free.fr> wrote:
"Alex Paris" <rbbt...@gmail.com> a écrit dans le message de news:
1186567318.592509.23...@22g2000hsm.googlegroups.com...
1. Il faut que tu implémentes une classe qui va te SERVIR pour la
gestion de matrices... analyse algèbre matricielle etc etc....
2. Il faut écrire une classe Matrix , template, avec un constructeur
de copie, destructor et opérateur =, implémenter les opération s de +,
- et * pour cette classe et montrer son utilisation pour le int !
(cours d'informatique à l'école)
Alors on peut avoir des longs débats sur comment rendre les matrices
etc super performantes et tout et tout... tandis que le problème n'e st
pas là : ) C'est pour avoir la NOTE !
La problématique est la même : pour augmenter tes chances d'avoir u ne bonne
note, il faut limiter le risque de faire des erreurs.
Du coup, tu aurais plutot interet à utiliser vector< vector< int > > plutot
qu'un int **.
Un vector de vector est la meilleur façon de tout planter.
Par exemple si un vecteur s'amuse à lancer une exception pendant un
changement de taille, je ne te parle pas de l'état de la matrice.
C'est certainement pas la solution que j'adopterais, non plus.
En revanche, je ne crois pas que les exceptions soient un
problème. Quoiqu'il arrive, on a une garantie faible sur les
données (c'est même un des avantages non négligible des
std::vector) ; on est sûr de pouvoir detruire l'objet, et de
faire le menage. Et franchement, garantir plus pourrait être
très cher si on compte changer les dimensions dynamiquement.
[...]
La méthode classique pour la représentation d'une matrice dense sans
autres caractéristiques (triangulaire, diagonale, creuse ...) est
d'utiliser un tableau unidimensionnel et d'utiliser operator()(int i,
int j){return (i*N+j);} pour acceder aux éléments.
Pour l'utilisation d'un tableau unidimensionnel, je suis tout à
fait d'accord. À mon avis, la seule question qui se pose, c'est
entre std::vector<T> et T*, avec allocation par appelle à la
fonction ::operator new (ou malloc(), mais pas utilisation de
l'opérateur new). Le dernier pourrait être intéressant dans
certains cas d'utilisation, à condition de bien savoir ce qu'on
fait. (Je le déconseillerais fort dans un projet d'école, en
revanche.)
En revanche, il y a bien deux écoles en ce qui concerne
l'interface. Ce que tu suggères suit Barton et Nackman, mais
d'autres ne sont pas de cet avis, et préfère définir
l'operator[] pour renvoyer un proxy, sur lequel l'operator[] est
également défini, ce qui permet l'écriture m[i][j]. (Je crois
que cette deuxième école est plus répandue. Et pour un projet
d'école, je me renseignerais sur l'école à laquelle adhère le
prof, et j'utiliserai celle-là. Ou j'implémenterais les deux,
avec des commentaires qui en expliquent les avantages et les
désavantages de chacun.)
A moins que ce ne soit demander (ou que le prof demande l'utilisation de
POD comme un tableau de valeurs), l'operateur de recopie n'est pas
nécessaire car tout est géré par le compilateur. Et c'est bien de
montrer qu'on sait ça aussi.
Pour une matrice, je ne sais pas. Pour commencer, je crois que
j'écrirais bien un constructeur de copie moi-même. Ne serait-ce
que pour empécher qu'il soit inline, et pour pouvoir
l'instrumenter à mon grè par la suite. Mais je m'arrangerais
surtout d'utiliser des proxy, de façon à ce que les copies
soient rarissimes. (Donc, par exemple, l'operator+ ne renverra
pas une matrice, mais seulement un proxy, qui pourrait servir de
construire une matrice, ou comme opérand d'un autre opérateur.)
Finalement, les opérateurs algébriques ont intérêt à être
définis en dehors de la classe.
Ça dépend, ça aussi. Au moins d'avoir des conversions
implicites, ça dépend de l'implémentation.
Il faut dire que des choses comme Matrix sont assez spéciales.
Elles servent surtout dans le calcul numérique, où on a assez
regulièrement des problèmes de vitesse. Alors, il faut prévoir
dès le départ la possibilité d'une phase d'optimisation. C-à-d
donc une encapsulation au maximum, pour qu'on peut changer tout
en travers s'il faut, sans modifier le code utilisateur. S'il
n'est pas question des conversions implicites, mettre les
opérateurs dans la classe améliore l'encapsulation.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
1. Il faut que tu implémentes une classe qui va te SERVIR pour la gestion de matrices... analyse algèbre matricielle etc etc.... 2. Il faut écrire une classe Matrix , template, avec un constructeur de copie, destructor et opérateur =, implémenter les opération s de +, - et * pour cette classe et montrer son utilisation pour le int ! (cours d'informatique à l'école)
Alors on peut avoir des longs débats sur comment rendre les matrices etc super performantes et tout et tout... tandis que le problème n'e st pas là : ) C'est pour avoir la NOTE !
La problématique est la même : pour augmenter tes chances d'avoir u ne bonne note, il faut limiter le risque de faire des erreurs.
Du coup, tu aurais plutot interet à utiliser vector< vector< int > > plutot qu'un int **.
Un vector de vector est la meilleur façon de tout planter. Par exemple si un vecteur s'amuse à lancer une exception pendant un changement de taille, je ne te parle pas de l'état de la matrice.
C'est certainement pas la solution que j'adopterais, non plus. En revanche, je ne crois pas que les exceptions soient un problème. Quoiqu'il arrive, on a une garantie faible sur les données (c'est même un des avantages non négligible des std::vector) ; on est sûr de pouvoir detruire l'objet, et de faire le menage. Et franchement, garantir plus pourrait être très cher si on compte changer les dimensions dynamiquement.
[...]
La méthode classique pour la représentation d'une matrice dense sans autres caractéristiques (triangulaire, diagonale, creuse ...) est d'utiliser un tableau unidimensionnel et d'utiliser operator()(int i, int j){return (i*N+j);} pour acceder aux éléments.
Pour l'utilisation d'un tableau unidimensionnel, je suis tout à fait d'accord. À mon avis, la seule question qui se pose, c'est entre std::vector<T> et T*, avec allocation par appelle à la fonction ::operator new (ou malloc(), mais pas utilisation de l'opérateur new). Le dernier pourrait être intéressant dans certains cas d'utilisation, à condition de bien savoir ce qu'on fait. (Je le déconseillerais fort dans un projet d'école, en revanche.)
En revanche, il y a bien deux écoles en ce qui concerne l'interface. Ce que tu suggères suit Barton et Nackman, mais d'autres ne sont pas de cet avis, et préfère définir l'operator[] pour renvoyer un proxy, sur lequel l'operator[] est également défini, ce qui permet l'écriture m[i][j]. (Je crois que cette deuxième école est plus répandue. Et pour un projet d'école, je me renseignerais sur l'école à laquelle adhère le prof, et j'utiliserai celle-là. Ou j'implémenterais les deux, avec des commentaires qui en expliquent les avantages et les désavantages de chacun.)
A moins que ce ne soit demander (ou que le prof demande l'utilisation de POD comme un tableau de valeurs), l'operateur de recopie n'est pas nécessaire car tout est géré par le compilateur. Et c'est bien de montrer qu'on sait ça aussi.
Pour une matrice, je ne sais pas. Pour commencer, je crois que j'écrirais bien un constructeur de copie moi-même. Ne serait-ce que pour empécher qu'il soit inline, et pour pouvoir l'instrumenter à mon grè par la suite. Mais je m'arrangerais surtout d'utiliser des proxy, de façon à ce que les copies soient rarissimes. (Donc, par exemple, l'operator+ ne renverra pas une matrice, mais seulement un proxy, qui pourrait servir de construire une matrice, ou comme opérand d'un autre opérateur.)
Finalement, les opérateurs algébriques ont intérêt à être définis en dehors de la classe.
Ça dépend, ça aussi. Au moins d'avoir des conversions implicites, ça dépend de l'implémentation.
Il faut dire que des choses comme Matrix sont assez spéciales. Elles servent surtout dans le calcul numérique, où on a assez regulièrement des problèmes de vitesse. Alors, il faut prévoir dès le départ la possibilité d'une phase d'optimisation. C-à-d donc une encapsulation au maximum, pour qu'on peut changer tout en travers s'il faut, sans modifier le code utilisateur. S'il n'est pas question des conversions implicites, mettre les opérateurs dans la classe améliore l'encapsulation.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
James Kanze
On Aug 8, 1:50 pm, Fabien LE LEZ wrote:
On Wed, 08 Aug 2007 13:27:52 +0200, Michael DOUBEZ :
Un vector de vector est la meilleur façon de tout planter. Par exemple si un vecteur s'amuse à lancer une exception pendant un changement de taille, je ne te parle pas de l'état de la matrice.
J'ose espérer que c'est du second degré.
(Pour ceux qui n'auraient pas compris : si un bug dans ton programme fait que vector lance une exception, le même bug aurait des conséquences bien plus graves (corruption de la mémoire, plantages aléatoires, etc.) avec un int**.
Il a bien dit « pendant un changement de taille ». Si on veut supporter le changement dynamique des dimensions de la matrice, il faut bien accepter la possibilité d'une exception, ne serait-ce que bad_alloc.
Je crois, d'ailleurs, que son souci soit précisement qu'en cas d'un bad_alloc, l'invariant myData[i].size() == myData[j].size(), pour tout i et j, risque fort de ne plus valoir. Si on accepte qu'après une exception, la matrice ne soit plus utilisable (ce qui me semble acceptable), avec les vecteurs embriqués, on est sûr de pouvoir toujours en appeler le destructeur, et de pas avoir une fuite de mémoire ou d'autres incohérences. (Mais ce n'est pas pour autant que ce soit une bonne solution.)
Je te dis pas l'état de la matrice si une exception est lancée dans la deuxième ligne d'un code du style delete[] data; data= new int [...]; )
Mais qui fait de conneries de ce genre ?
Note par ailleurs qu'il est relativement facile, avec vector<>::swap() par exemple, de rendre la classe "strongly exception-safe" (i.e. en cas d'exception, l'objet est dans le même état qu'avant l'appel à la fonction).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
On Aug 8, 1:50 pm, Fabien LE LEZ <grams...@gramster.com> wrote:
On Wed, 08 Aug 2007 13:27:52 +0200, Michael DOUBEZ
<michael.dou...@free.fr>:
Un vector de vector est la meilleur façon de tout planter.
Par exemple si un vecteur s'amuse à lancer une exception pendant un
changement de taille, je ne te parle pas de l'état de la matrice.
J'ose espérer que c'est du second degré.
(Pour ceux qui n'auraient pas compris : si un bug dans ton programme
fait que vector lance une exception, le même bug aurait des
conséquences bien plus graves (corruption de la mémoire, plantages
aléatoires, etc.) avec un int**.
Il a bien dit « pendant un changement de taille ». Si on veut
supporter le changement dynamique des dimensions de la matrice,
il faut bien accepter la possibilité d'une exception, ne
serait-ce que bad_alloc.
Je crois, d'ailleurs, que son souci soit précisement qu'en cas
d'un bad_alloc, l'invariant myData[i].size() ==
myData[j].size(), pour tout i et j, risque fort de ne plus
valoir. Si on accepte qu'après une exception, la matrice ne
soit plus utilisable (ce qui me semble acceptable), avec les
vecteurs embriqués, on est sûr de pouvoir toujours en appeler le
destructeur, et de pas avoir une fuite de mémoire ou d'autres
incohérences. (Mais ce n'est pas pour autant que ce soit une
bonne solution.)
Je te dis pas l'état de la matrice si une exception est lancée dans la
deuxième ligne d'un code du style
delete[] data;
data= new int [...];
)
Mais qui fait de conneries de ce genre ?
Note par ailleurs qu'il est relativement facile, avec vector<>::swap()
par exemple, de rendre la classe "strongly exception-safe" (i.e. en
cas d'exception, l'objet est dans le même état qu'avant l'appel à la
fonction).
On Wed, 08 Aug 2007 13:27:52 +0200, Michael DOUBEZ :
Un vector de vector est la meilleur façon de tout planter. Par exemple si un vecteur s'amuse à lancer une exception pendant un changement de taille, je ne te parle pas de l'état de la matrice.
J'ose espérer que c'est du second degré.
(Pour ceux qui n'auraient pas compris : si un bug dans ton programme fait que vector lance une exception, le même bug aurait des conséquences bien plus graves (corruption de la mémoire, plantages aléatoires, etc.) avec un int**.
Il a bien dit « pendant un changement de taille ». Si on veut supporter le changement dynamique des dimensions de la matrice, il faut bien accepter la possibilité d'une exception, ne serait-ce que bad_alloc.
Je crois, d'ailleurs, que son souci soit précisement qu'en cas d'un bad_alloc, l'invariant myData[i].size() == myData[j].size(), pour tout i et j, risque fort de ne plus valoir. Si on accepte qu'après une exception, la matrice ne soit plus utilisable (ce qui me semble acceptable), avec les vecteurs embriqués, on est sûr de pouvoir toujours en appeler le destructeur, et de pas avoir une fuite de mémoire ou d'autres incohérences. (Mais ce n'est pas pour autant que ce soit une bonne solution.)
Je te dis pas l'état de la matrice si une exception est lancée dans la deuxième ligne d'un code du style delete[] data; data= new int [...]; )
Mais qui fait de conneries de ce genre ?
Note par ailleurs qu'il est relativement facile, avec vector<>::swap() par exemple, de rendre la classe "strongly exception-safe" (i.e. en cas d'exception, l'objet est dans le même état qu'avant l'appel à la fonction).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
James Kanze
On Aug 8, 3:52 pm, Alex Paris wrote:
On 8 août, 14:11, "Christophe Lephay" wrote:
De mon coté, je n'en serais pas surpris. Le C++ et le C++ enseigné par certains professeur n'ont parfois que le nom en commun. J'ai déjà rencontré des profs d'info enseignant le C++ qui n'avaient jamais entendu parlé de vector (c'était il y a à peu pret 5 ans, les vector n'étaient donc pas une nouveauté). Dans la foulée, les profs qui ne maitrisent pas leur sujet sont souvent réfractaires aux notions qu'ils ne connaissent pas, impossible qu'ils sont d'accepter l'idée qu'un de leur étudiants puisse connaitre quelque chose qu'eux-mêmes ignorent.
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on parle de C++ ?
Ce n'est pas obligatoire, mais la bibliothèque standard fait bien partie du langage. Surtout, le type "standard" du tableau, en C++, c'est bien std::vector. Les autres types (les T[] de C, std::deque, etc.) ne servent que dans les cas particuliers. Surtout les T[], qu'on n'utilise pratiquement que pour des variables de durée de vie statique, afin de permettre une initialisation statique (ou sinon, quand le profiler dit qu'il faut).
Je suis d'accord que dans le cadre professionnel il est fortement conseillé d'utiliser les librairies mais pour les exercices d'études tu peux très bien te base sur la notion du langage même en état pur.
Surtout dans les exércises d'étude, le type d'un tableau est toujours std::vector, dans le C++ bien enseigné. L'utilisation des T[] est assez complexe, et on ne les présente que quand on abord les questions d'ordre d'initialisation des objets statiques. Ou dans un cours de programmation système, où on apprend à implémenter la bibliothèque standard.
En ce qui concerne cout/cerr et I/O c'est une question de choix quoi qu'il en soit tu es obligé de montrer tes résultat.
Ce n'est donc pas une question de choix:-).
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui gère ... (patati patata... regarde plus haut)... d'après moi il n'est pas question de montrer tes connaissance en STL.
Je ne sais pas. Pour implémenter une classe Matrix, il va bien falloir un tableau. Et le premier type de tableau que connaitra un débuttant, c'est bien std::vector.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
On Aug 8, 3:52 pm, Alex Paris <rbbt...@gmail.com> wrote:
On 8 août, 14:11, "Christophe Lephay" <christophe-lep...@wanadoo.fr>
wrote:
De mon coté, je n'en serais pas surpris. Le C++ et le C++
enseigné par certains professeur n'ont parfois que le nom en
commun. J'ai déjà rencontré des profs d'info enseignant le
C++ qui n'avaient jamais entendu parlé de vector (c'était il
y a à peu pret 5 ans, les vector n'étaient donc pas une
nouveauté). Dans la foulée, les profs qui ne maitrisent pas
leur sujet sont souvent réfractaires aux notions qu'ils ne
connaissent pas, impossible qu'ils sont d'accepter l'idée
qu'un de leur étudiants puisse connaitre quelque chose
qu'eux-mêmes ignorent.
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on
parle de C++ ?
Ce n'est pas obligatoire, mais la bibliothèque standard fait
bien partie du langage. Surtout, le type "standard" du tableau,
en C++, c'est bien std::vector. Les autres types (les T[] de C,
std::deque, etc.) ne servent que dans les cas particuliers.
Surtout les T[], qu'on n'utilise pratiquement que pour des
variables de durée de vie statique, afin de permettre une
initialisation statique (ou sinon, quand le profiler dit qu'il
faut).
Je suis d'accord que dans le cadre professionnel il est
fortement conseillé d'utiliser les librairies mais pour les
exercices d'études tu peux très bien te base sur la notion du
langage même en état pur.
Surtout dans les exércises d'étude, le type d'un tableau est
toujours std::vector, dans le C++ bien enseigné. L'utilisation
des T[] est assez complexe, et on ne les présente que quand on
abord les questions d'ordre d'initialisation des objets
statiques. Ou dans un cours de programmation système, où on
apprend à implémenter la bibliothèque standard.
En ce qui concerne cout/cerr et I/O c'est une question de
choix quoi qu'il en soit tu es obligé de montrer tes résultat.
Ce n'est donc pas une question de choix:-).
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui
gère ... (patati patata... regarde plus haut)... d'après moi il n'est
pas question de montrer tes connaissance en STL.
Je ne sais pas. Pour implémenter une classe Matrix, il va bien
falloir un tableau. Et le premier type de tableau que connaitra
un débuttant, c'est bien std::vector.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
De mon coté, je n'en serais pas surpris. Le C++ et le C++ enseigné par certains professeur n'ont parfois que le nom en commun. J'ai déjà rencontré des profs d'info enseignant le C++ qui n'avaient jamais entendu parlé de vector (c'était il y a à peu pret 5 ans, les vector n'étaient donc pas une nouveauté). Dans la foulée, les profs qui ne maitrisent pas leur sujet sont souvent réfractaires aux notions qu'ils ne connaissent pas, impossible qu'ils sont d'accepter l'idée qu'un de leur étudiants puisse connaitre quelque chose qu'eux-mêmes ignorent.
C'est depuis quand l'utilisation de STL est obligatoire lorsqu'on parle de C++ ?
Ce n'est pas obligatoire, mais la bibliothèque standard fait bien partie du langage. Surtout, le type "standard" du tableau, en C++, c'est bien std::vector. Les autres types (les T[] de C, std::deque, etc.) ne servent que dans les cas particuliers. Surtout les T[], qu'on n'utilise pratiquement que pour des variables de durée de vie statique, afin de permettre une initialisation statique (ou sinon, quand le profiler dit qu'il faut).
Je suis d'accord que dans le cadre professionnel il est fortement conseillé d'utiliser les librairies mais pour les exercices d'études tu peux très bien te base sur la notion du langage même en état pur.
Surtout dans les exércises d'étude, le type d'un tableau est toujours std::vector, dans le C++ bien enseigné. L'utilisation des T[] est assez complexe, et on ne les présente que quand on abord les questions d'ordre d'initialisation des objets statiques. Ou dans un cours de programmation système, où on apprend à implémenter la bibliothèque standard.
En ce qui concerne cout/cerr et I/O c'est une question de choix quoi qu'il en soit tu es obligé de montrer tes résultat.
Ce n'est donc pas une question de choix:-).
Mais lorsqu'on te demande de FAIRE une classe template Matrix qui gère ... (patati patata... regarde plus haut)... d'après moi il n'est pas question de montrer tes connaissance en STL.
Je ne sais pas. Pour implémenter une classe Matrix, il va bien falloir un tableau. Et le premier type de tableau que connaitra un débuttant, c'est bien std::vector.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Laurent Deniau
On 7 août, 19:37, Fabien LE LEZ wrote:
On Tue, 07 Aug 2007 09:17:09 -0700, Alex Paris :
Non mais en réalité l'exemple est super simplifié. Il y a une donn ée _data qui contient tout la structure... le tableu en fait. Si c'est déclaré T** je ne pense pas que le compilo sera capable de tout recopier correctement.
En d'autres termes, tu as deux[*] fonctionnalités différentes : - d'une part, la gestion de mémoire ; - d'autre part, l'interface de Matrix, i.e. la partie "mathématiques".
en realite il y en a au minimum 4 si on veut qqchose de flexible:
et pour ce qui est de reinventer la roue, les valarray sont un bon point de depart pour l'implementation des trois derniers points.
a+, ld.
On 7 août, 19:37, Fabien LE LEZ <grams...@gramster.com> wrote:
On Tue, 07 Aug 2007 09:17:09 -0700, Alex Paris <rbbt...@gmail.com>:
Non mais en réalité l'exemple est super simplifié. Il y a une donn ée
_data qui contient tout la structure... le tableu en fait. Si c'est
déclaré T** je ne pense pas que le compilo sera capable de tout
recopier correctement.
En d'autres termes, tu as deux[*] fonctionnalités différentes :
- d'une part, la gestion de mémoire ;
- d'autre part, l'interface de Matrix, i.e. la partie
"mathématiques".
en realite il y en a au minimum 4 si on veut qqchose de flexible:
Non mais en réalité l'exemple est super simplifié. Il y a une donn ée _data qui contient tout la structure... le tableu en fait. Si c'est déclaré T** je ne pense pas que le compilo sera capable de tout recopier correctement.
En d'autres termes, tu as deux[*] fonctionnalités différentes : - d'une part, la gestion de mémoire ; - d'autre part, l'interface de Matrix, i.e. la partie "mathématiques".
en realite il y en a au minimum 4 si on veut qqchose de flexible:
et pour ce qui est de reinventer la roue, les valarray sont un bon point de depart pour l'implementation des trois derniers points.
a+, ld.
Fabien LE LEZ
On Thu, 09 Aug 2007 07:53:52 -0000, James Kanze :
Quoiqu'il arrive, on a une garantie faible sur les données (c'est même un des avantages non négligible des std::vector) ; on est sûr de pouvoir detruire l'objet, et de faire le menage. Et franchement, garantir plus pourrait être très cher si on compte changer les dimensions dynamiquement.
Si on veut agrandir progressivement un tableau (push_back), ou le réduire, alors effectivement il y a un souci de performances.
Par contre, si on veut changer radicalement la taille d'un tableau, il y a de bonnes chances pour qu'on doive recopier les données de toutes façons.
Il me semble que ces deux codes ont les mêmes performances :
vector<T> v (12); v.resize (120);
vector<T> v (12); vector<T> temp (120); temp.swap (v);
On Thu, 09 Aug 2007 07:53:52 -0000, James Kanze
<james.kanze@gmail.com>:
Quoiqu'il arrive, on a une garantie faible sur les
données (c'est même un des avantages non négligible des
std::vector) ; on est sûr de pouvoir detruire l'objet, et de
faire le menage. Et franchement, garantir plus pourrait être
très cher si on compte changer les dimensions dynamiquement.
Si on veut agrandir progressivement un tableau (push_back), ou le
réduire, alors effectivement il y a un souci de performances.
Par contre, si on veut changer radicalement la taille d'un tableau, il
y a de bonnes chances pour qu'on doive recopier les données de toutes
façons.
Il me semble que ces deux codes ont les mêmes performances :
vector<T> v (12);
v.resize (120);
vector<T> v (12);
vector<T> temp (120);
temp.swap (v);
Quoiqu'il arrive, on a une garantie faible sur les données (c'est même un des avantages non négligible des std::vector) ; on est sûr de pouvoir detruire l'objet, et de faire le menage. Et franchement, garantir plus pourrait être très cher si on compte changer les dimensions dynamiquement.
Si on veut agrandir progressivement un tableau (push_back), ou le réduire, alors effectivement il y a un souci de performances.
Par contre, si on veut changer radicalement la taille d'un tableau, il y a de bonnes chances pour qu'on doive recopier les données de toutes façons.
Il me semble que ces deux codes ont les mêmes performances :
vector<T> v (12); v.resize (120);
vector<T> v (12); vector<T> temp (120); temp.swap (v);