OVH Cloud OVH Cloud

Tableaux et stl

42 réponses
Avatar
JM
Bonjour

Toujours plongé dans la stl, j'ai quelques questions (Pas évident de
trouver un tutoriel à la fois clair et compréhensible)

0) Où peut-on trouver un bon tutoriel (Français de préférence, mais à
défaut, l'anglais me conviendra)

1)
J'ai une classe :
class CA
{public
CA() { initialisations divers et variées; }
~CA();

void f();
}

vector<CA> tableau;

tableau.size(10);

Le constructeur est-il bien appelé pour les 10 éléments?
Je pense que oui mais le doute est en moi.

2) Toujours avec la classe précédente.

Je veux ajouter un élément à la fin de mon tableau.
A priori, tableau.push_back ne peut-être utilisé sans passer de référence.

J'ai essayé deux trucs :
a) tableau.push_back(CA());

Vu que cela crée un objet temporaire sur la pile, cela ne me
convient pas trop.

b) tableau.resize(tableau.size()+1)

Cela me parait un peu bourrin, mais c'est le seul truc que j'ai pu
trouver dans les tutoriels que j'ai vus.


y'a-t-il d'autres possibilités, sachant que toutes les initialisations
dont j'ai besoin sont faites dans le constructeur?

3) Jusqu'à présent, style C oblige, j'utilisais toujours une variable
pour conserver la taille de mon tableau.

Je suppose que cette manière de faire est obsolète avec size() ?

Merci d'avance à ceux qui répondront à ces questions certainement niveau
0, mais j'avoue que cela m'aidera bien!

10 réponses

1 2 3 4 5
Avatar
kanze
loufoque wrote:

j'aime cette philosophie, la coexistence de variables
statiques ET dynamiques me va très bien également; non, je
ne vois pas comment efficacement sans passer.


Ben justement, il ne devrait pas y avoir coexistance.


Bien sûr que si. C'est une des forces de C++, de supporter
plusieurs paradigmes. En l'occurance, selon la rôle du type dans
l'application, il risque d'avoir soit une sémantique de valeur,
soit une sémantique d'entité ; dans le premier cas, des
allocations dynamiques seront extrèmement rare (de même que je
ne vois gère d'intérêt dans « new int »), dans le deuxième, il
est probable que toutes les instances soient allouées
dynamiquement.

À un niveau plus bas, aussi, dans l'implémentation d'une valeur,
on peut choisir parfois d'allouer dynamiquement, parfois non, et
ça, dans certains cas, même à l'intérieur d'un seul type.
(Beaucoup des implémentations de std::string, par exemple, ont
un buffer local, et n'alloue dynamiquement que si la capacité
requise dépasse la taille du buffer -- c'est connu sous la
vocable de « small string optimization », en anglais.)

Si tu veux du code de qualité, c'est-à-dire du code
exception-safe, toute donnée allouée dynamiquement est stockée
dans un conteneur qui gère sa durée de vie et qui répond à des
sémantiques de valeur.


Pas du tout.

En général, il y a bien des utilisations de la mémoire dynamique
dans l'implémentation des types à sémantique de valeur, mais
cette utilisation est en général transparente aux clients du
type. Au niveau de l'application (c-à-d que tu n'es pas en train
d'implémenter de tels objets), pratiquement toutes les
allocations dynamiques concernent les objets d'entité. Et les
objets d'entité n'ont pas du tout une sémantique de valeur, tout
au contraire. On les crée suite à un évenemment (requête
utilisateur, etc.), et on les detruire suite à un autre
évenement. Au moins qu'ils n'existent toute la durée d'exécution
de l'application.

Et pour les exceptions, au moins qu'ils ont une sémantique
particulière associée à la fin de leur vie (ce qui est quand
même assez exceptionnel), le glaneur de cellules s'en occupe
très bien. Et c'est plus facile d'installer et de configurer le
collecteur de Boehm que d'installer et de configurer Boost, pour
avoir shared_ptr. (Mais ça vaut la peine d'installer Boost et de
s'en servir pour beaucoup d'autres raisons.)

Donc le dynamique c'est uniquement dans des couches plus
basses.


Au contraire. Si c'est vrai que les couches les plus basses
(p.e. l'implémentation de std::basic_string) puisse se servir de
la mémoire dynamique, pour quelqu'un qui n'écrit pas de telles
bibliothèques, le dynamique sert surtout pour les objets
d'entité, c-à-d typiquement dans la couche la plus haute.

je suis également d'accord avec les exigences du contrat de
vector<>, je soulignais le trait pour indiquer qu'il a
*IMHO* un caractère négatif.


Il n'y a pas de caractère négatif, c'est juste qu'on peut pas
faire autrement pour stocker des valeurs.


C-à-d qu'il se comporte comme un T[], à ce niveau-là.

[...]
l'organisation interne de vector<> passe nécessairement par des
pointeurs de la classe template


Non.
Comme il a déjà été dit, on stocke des T, pas des T*. Je sais
pas d'où te vient l'idée qu'on stocke des pointeurs des
données et pas les données elles-mêmes.

Tu aurais pourtant du, dans ton apprentissage du C++, réecrire
un truc semblable à std::vector.


Qu'il y a des lacunes dans la connaissance de la STL chez
Sylvain, c'est fort possible. Mais j'imagine quand même mal
quelqu'un qui a réécri un truc semblable de std::vector dans
leur apprentissage. Écrire un truc pareil exige l'utilisation
d'un certain nombre d'astuces que le programmeur moyen n'a pas
vraiment besoin de connaître (comme la séparation de
l'allocation et de l'initialisation), et qui font partie
vraiement du C++ avancé.

si la question était ouverte ("si" parce que heureusement
99% des utilisateurs se foutent de l'avis qui suit), le
mérite de vector<> est son mécanisme allocator customisable


Oui enfin, ça sert uniquement à utiliser des mécanismes comme
le pooling, ce qui est plus le travail du système
d'exploitation et de l'environnement.


Pas forcément. Je m'en suis déjà servi dans un std::map, pour le
mettre dans de la mémoire partagée entre plusieurs processus.
(Mais comme j'ai dit, historiquement, c'était pour pouvoir créer
un std::vector de plus de 64 Ko tout en compilant en modèle
small.)

--
James Kanze GABI Software
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


Avatar
loufoque

Et pour les exceptions, au moins qu'ils ont une sémantique
particulière associée à la fin de leur vie (ce qui est quand
même assez exceptionnel), le glaneur de cellules s'en occupe
très bien. Et c'est plus facile d'installer et de configurer le
collecteur de Boehm que d'installer et de configurer Boost, pour
avoir shared_ptr. (Mais ça vaut la peine d'installer Boost et de
s'en servir pour beaucoup d'autres raisons.)


Tu supposes l'utilisation d'un ramasse-miettes (tiens, je connaissais
pas le terme "glaneur de cellules") ce qui te permet effectivement de ne
pas avoir à "wrapper" tes pointeurs vers des objets alloués
dynamiquement dans des objets à gestion mémoire automatique.
Néanmoins si on n'utilise pas ce genre de choses cela devrait être fait,
que ce soit dans des shared_ptr ou dans des trucs plus appropriés.

Je ne suis pas non plus un grand fan des shared_ptr.
En fait dans les développements que j'ai fait je n'ai jamais eu besoin
de ce genre de choses, mais cela vient sûrement du fait que je n'ai
jamais été confronté à des contraintes business, que je code plutôt des
trucs expérimentaux pour mon plaisir et que j'utilise très peu le
polymorphisme (pour du pimpl essentiellement) préférant la généricité.


Qu'il y a des lacunes dans la connaissance de la STL chez
Sylvain, c'est fort possible. Mais j'imagine quand même mal
quelqu'un qui a réécri un truc semblable de std::vector dans
leur apprentissage. Écrire un truc pareil exige l'utilisation
d'un certain nombre d'astuces que le programmeur moyen n'a pas
vraiment besoin de connaître (comme la séparation de
l'allocation et de l'initialisation), et qui font partie
vraiement du C++ avancé.


Truc semblable c'est à dire fort simplifié.
Il me paraît tout de même important de savoir réecrire les structures de
données pour savoir exactement comment elles fonctionnent et pouvoir en
déduire le coût de chacune des opérations.


Pas forcément. Je m'en suis déjà servi dans un std::map, pour le
mettre dans de la mémoire partagée entre plusieurs processus.
(Mais comme j'ai dit, historiquement, c'était pour pouvoir créer
un std::vector de plus de 64 Ko tout en compilant en modèle
small.)


Oui en effet il y a aussi la possibilité de la mémoire partagée.
Mais bon dans ce cas-là ça ne s'utilise pas "normalement", il faut
passer par un framework genre boost.interprocess (anciennement boost.shmem)

J'ai jamais eu l'occasion d'utiliser ce genre de trucs cependant. Quand
je dois faire communiquer des processus j'utilise plutôt des pipes ou
des sockets.

Avatar
Sylvain
loufoque wrote on 20/09/2006 16:17:

Et pour les exceptions, au moins qu'ils ont une sémantique
particulière associée à la fin de leur vie (ce qui est quand
même assez exceptionnel), le glaneur de cellules s'en occupe
très bien. [...]


Tu supposes l'utilisation d'un ramasse-miettes [...]
Néanmoins si on n'utilise pas ce genre de choses cela devrait être fait,
que ce soit dans des shared_ptr ou dans des trucs plus appropriés.


un "truc" comme un beau pointeur global ?

[...] je code plutôt des
trucs expérimentaux pour mon plaisir et que j'utilise très peu le
polymorphisme (pour du pimpl essentiellement) préférant la généricité.


?!? tu peux m'expliquer "traitement polymorphe" vs "traitement
générique", stp ?
peut-être penses-tu à ce que l'on nomme parfois un "polymorphisme
statique" (ie des classes templates).

Tu aurais pourtant du, dans ton apprentissage du C++, réecrire
un truc semblable à std::vector.




hein ??!!??

il me semble que Stepanov a présenté ce projet au comité ANSI/ISO C++
entre fin 1993 et début 1994; à cette date, vois-tu, je n'étais plus à
l'école!

Qu'il y a des lacunes dans la connaissance de la STL chez
Sylvain, c'est fort possible.



ça je confirme, sans hésitation.

Mais j'imagine quand même mal
quelqu'un qui a réécri un truc semblable de std::vector dans
leur apprentissage. Écrire un truc pareil exige l'utilisation
d'un certain nombre d'astuces que le programmeur moyen n'a pas
vraiment besoin de connaître [...], et qui font partie
vraiement du C++ avancé.


Truc semblable c'est à dire fort simplifié.
Il me paraît tout de même important de savoir réecrire les structures de
données pour savoir exactement comment elles fonctionnent et pouvoir en
déduire le coût de chacune des opérations.


je sais écrire des "trucs" qui s'adaptent à ma ""philosophie"" (ici un
vecteur de T* qui retourne des T&), pour autant comprendre l'intérêt des
algo de la STL et en évaluer le coût, ne requiert pas IMHO de réécrire
la même chose (si on obtient bien la "même chose" autant utiliser
l'original, si - plus vraisemblable - on empile les erreurs de
compréhension et de codage, on mesurera un truc sans rapport).

[] mettre dans de la mémoire partagée entre plusieurs processus.
J'ai jamais eu l'occasion d'utiliser ce genre de trucs cependant. Quand

je dois faire communiquer des processus j'utilise plutôt des pipes ou
des sockets.


James parlait de *partage* de données (une donnée dispo pour plusieurs
process distincts) pas de *communication* d'une donnée entre process.

sous Windows qui propose (impose) des APIs spécifiques pour de tels
données partagées, les allocators sont très utiles, sur PDA pour gérer
des objets persistants sur différentes cartes mémoires également (ce ne
sont que des exemples).

Sylvain.



Avatar
Fabien LE LEZ
On Wed, 20 Sep 2006 16:17:17 +0200, loufoque
:

(tiens, je connaissais
pas le terme "glaneur de cellules")


C'est un sale hack pour avoir les mêmes initiales que garbage
collector.
Z'auraient dû appeler ça "Garibaldi contrarié", ça aurait été plus
sympa...

Avatar
loufoque

un "truc" comme un beau pointeur global ?


Si l'objet doit exister jusqu'à la fermeture du programme, ça convient.
Mais bon c'est pas vraiment de ça que je parlais.


?!? tu peux m'expliquer "traitement polymorphe" vs "traitement
générique", stp ?
peut-être penses-tu à ce que l'on nomme parfois un "polymorphisme
statique" (ie des classes templates).


Ça dépend du sens qu'on donne à polymorphisme, je parlais du
polymorphisme dynamique d'inclusion, qui introduit un coût à l'exécution
via l'utilisation de fonctions membres virtuelles et qui s'utilise via
des pointeurs ou références sur des bases.
Je préfère l'usage des templates avec notamment le policy-based design.


hein ??!!??

il me semble que Stepanov a présenté ce projet au comité ANSI/ISO C++
entre fin 1993 et début 1994; à cette date, vois-tu, je n'étais plus à
l'école!


Quel rapport ?
Si tu veux développer en C++, il faut bien apprendre à un moment ou à un
autre. Que ce soit à l'école, en autodidacte, ou dans un stage.


je sais écrire des "trucs" qui s'adaptent à ma ""philosophie"" (ici un
vecteur de T* qui retourne des T&), pour autant comprendre l'intérêt des
algo de la STL et en évaluer le coût, ne requiert pas IMHO de réécrire
la même chose (si on obtient bien la "même chose" autant utiliser
l'original, si - plus vraisemblable - on empile les erreurs de
compréhension et de codage, on mesurera un truc sans rapport).


Un des avantages de C++ est que les structures de données ne sont pas
dans le langage. Savoir donc comment en créer une avec celui-ci me
paraît important.
D'autant plus que savoir écrire les structures de données usuelles de
manière générique est une connaissance que chaque développeur devrait
avoir. Il me semble d'ailleurs que ce genre de chose est enseigné en
début de tout cursus d'études en informatique en algorithmie.

Il faut effectivement mieux utiliser l'original qui est sûrement testé
et optimisé.
À part bien sûr dans les cas où tu as besoin de choses plus personnalisées.


James parlait de *partage* de données (une donnée dispo pour plusieurs
process distincts) pas de *communication* d'une donnée entre process.


Je sais ce qu'est la mémoire partagée.
Pour travailler avec plusieurs processus cependant je n'en ai pas eu
besoin, préférant la communication.


sous Windows qui propose (impose) des APIs spécifiques pour de tels
données partagées, les allocators sont très utiles, sur PDA pour gérer
des objets persistants sur différentes cartes mémoires également (ce ne
sont que des exemples).


Je vois pas trop l'intérêt d'avoir des choses persistantes en dehors
d'un programme (à part sous l'aspect d'une base de données).
Autant utiliser un serveur d'applications, non ?
Enfin c'est vrai que dans l'embarqué, la machine elle-même est plus ou
moins un serveur d'applications.

Avatar
kanze
loufoque wrote:

Et pour les exceptions, au moins qu'ils ont une sémantique
particulière associée à la fin de leur vie (ce qui est quand
même assez exceptionnel), le glaneur de cellules s'en occupe
très bien. Et c'est plus facile d'installer et de configurer le
collecteur de Boehm que d'installer et de configurer Boost, pour
avoir shared_ptr. (Mais ça vaut la peine d'installer Boost et de
s'en servir pour beaucoup d'autres raisons.)


Tu supposes l'utilisation d'un ramasse-miettes (tiens, je connaissais
pas le terme "glaneur de cellules") ce qui te permet effectivement de ne
pas avoir à "wrapper" tes pointeurs vers des objets alloués
dynamiquement dans des objets à gestion mémoire automatique.


C'est vrai que je conçois mal commencer un projet C++
aujourd'hui sans Boost ni le collecteur de Boehm. Ni l'un ni
l'autre ne fait partie de la norme (encore), mais les deux sont
assez portables, et se rendent de services importantes.

Néanmoins si on n'utilise pas ce genre de choses cela devrait être fa it,
que ce soit dans des shared_ptr ou dans des trucs plus appropriés.


Non plus. Une des raisons pourquoi un glaneur de cellules est si
important, c'est précisement parce que les alternatives du genre
shared_ptr ne suffisent pas. Qu'on les utilise pour certaines
choses, certes, mais c'est loin d'être une solution univerelle.

Je ne suis pas non plus un grand fan des shared_ptr.
En fait dans les développements que j'ai fait je n'ai jamais eu besoin
de ce genre de choses, mais cela vient sûrement du fait que je n'ai
jamais été confronté à des contraintes business, que je code plut ôt des
trucs expérimentaux pour mon plaisir et que j'utilise très peu le
polymorphisme (pour du pimpl essentiellement) préférant la généri cité.


Je conçois bien que beaucoup dépend de l'application. Dans mon
cas, j'ai de l'expérence importante dans deux domaines
distincts : la banque (côté gestion des comptes, etc. -- très
peu sur les logiciels de marché), et la téléphonie (côté
opérationnelle). A priori, je crois que ces expériences
s'exterpôlent assez bien vers une bonne partie de la gestion ou
du contrôle en temps-réel ; c'est certain, en revanche, qu'il y
a des domaines tout à fait différents, genre jeux ou les
applications numériques de recherche.

Ce qui est commun à toutes mes applications, c'est qu'on modèle
une partie du domaine d'application au moyen des objets
d'entité ; ces objets apparaissent et s'en vont en fonction des
évenemments extérieurs. Et que la plupart des autres types sont
des types de valeur, qui ne sont jamais alloués dynamiquement.

Qu'il y a des lacunes dans la connaissance de la STL chez
Sylvain, c'est fort possible. Mais j'imagine quand même mal
quelqu'un qui a réécri un truc semblable de std::vector dans
leur apprentissage. Écrire un truc pareil exige l'utilisation
d'un certain nombre d'astuces que le programmeur moyen n'a pas
vraiment besoin de connaître (comme la séparation de
l'allocation et de l'initialisation), et qui font partie
vraiement du C++ avancé.


Truc semblable c'est à dire fort simplifié.
Il me paraît tout de même important de savoir réecrire les structur es de
données pour savoir exactement comment elles fonctionnent et pouvoir en
déduire le coût de chacune des opérations.


Mais jusqu'où ? Une partie fondamentale des collections STL,
c'est la séparation de l'allocation et de l'initialisation. Une
possibilité du C++ qui m'a servi aussi dans mes collections
pré-norme. Mais une possibilité qui ne m'a jamais servi que pour
l'implémentation de de telles classes, qui ne fait pas
forcément partie du bagage du programmeur C++ de base, et qui ne
doit certainement pas faire partie des cours de base de C++.

Pas forcément. Je m'en suis déjà servi dans un std::map, pour le
mettre dans de la mémoire partagée entre plusieurs processus.
(Mais comme j'ai dit, historiquement, c'était pour pouvoir créer
un std::vector de plus de 64 Ko tout en compilant en modèle
small.)


Oui en effet il y a aussi la possibilité de la mémoire partagée.
Mais bon dans ce cas-là ça ne s'utilise pas "normalement", il faut
passer par un framework genre boost.interprocess (anciennement boost.shme m)


Pourquoi ? Il faut bien synchroniser les accès ; dans notre
cas, on s'est servi des pthread_rwlock directement. Sinon, on
a remplacé l'allocateur, et ça a suffi. (La mémoire partagée, en
l'occurance, venait de mmap. Je ne sais pas pourquoi, mais c'est
beaucoup plus simple et plus efficace que le shmem de Posix.)

J'ai jamais eu l'occasion d'utiliser ce genre de trucs cependant. Quand
je dois faire communiquer des processus j'utilise plutôt des pipes ou
des sockets.


En général, moi aussi. C'était un cas exceptionnel.

--
James Kanze GABI Software
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


Avatar
kanze
Sylvain wrote:
loufoque wrote on 20/09/2006 16:17:

Et pour les exceptions, au moins qu'ils ont une sémantique
particulière associée à la fin de leur vie (ce qui est quand
même assez exceptionnel), le glaneur de cellules s'en occupe
très bien. [...]


Tu supposes l'utilisation d'un ramasse-miettes [...]
Néanmoins si on n'utilise pas ce genre de choses cela devrait être fait,
que ce soit dans des shared_ptr ou dans des trucs plus appropriés.


un "truc" comme un beau pointeur global ?


Tout dépend, mais je me sers encore beaucoup des pointeurs
bruts. (C'est ce que je crois que tu veux dire. Des variables
globales, pointeur ou d'autres, il y en a fort peu dans mes
programmes.)

La plupart du temps, quand je me sers d'un pointeur intelligent,
ce n'est pas que pour la gestion de la durée de vie ; c'est
vraiment une question d'« ownership ». Donc, par exemple, dans
mes interfaces entre des threads, je me sers beaucoup
d'auto_ptr -- une fois que la propriété de l'objet a été passé
à l'autre thread, l'accès dans le premier thread devient
impossible.

(En passant : pourquoi est-ce que parler de l'« ownership »
d'un objet me semble tout à fait naturel en anglais, mais que
l'utilisation du mot « propriété » dans le même contexte en
français ne me semble pas juste ?)

[...] je code plutôt des
trucs expérimentaux pour mon plaisir et que j'utilise très peu le
polymorphisme (pour du pimpl essentiellement) préférant la géné ricité.


?!? tu peux m'expliquer "traitement polymorphe" vs "traitement
générique", stp ?


C'est qu'il utilise le vocabulaire détourné de la STL. Où les
itérateurs ne sont pas de vrais itérateurs, et la généricité est
limitée à la compilation:-).

peut-être penses-tu à ce que l'on nomme parfois un "polymorphisme
statique" (ie des classes templates).


De même façon que dans le langage courant de l'informatique en
dehors de la communité C++, la généricité s'implémente souvent
au moyen de l'héritage.

Tu aurais pourtant du, dans ton apprentissage du C++, réecrire
un truc semblable à std::vector.




hein ??!!??

il me semble que Stepanov a présenté ce projet au comité ANSI/ISO C ++
entre fin 1993 et début 1994; à cette date, vois-tu, je n'étais plu s à
l'école!


Ce qui veut dire alors que tu as dû implémenter quelque chose de
semblable, parce qu'avant, on n'avait que ce qu'on avait
implémenté nous-même. (En fait, il y avait de bonnes
bibliothèques disponibles : USL, Booch, etc. Mais pour diverses
raisons politiques, on ne pouvait pas toujours s'en servir.)

--
James Kanze GABI Software
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




Avatar
kanze
loufoque wrote:

un "truc" comme un beau pointeur global ?


Si l'objet doit exister jusqu'à la fermeture du programme, ça
convient. Mais bon c'est pas vraiment de ça que je parlais.


Mais de quels objets est-ce que tu parlais ? Je n'utilise pas
l'allocation dynamique pour des objets de type valeur, qui sont
soit sur la pile, soit des membres d'autres classes. Je
l'utilise surtout pour des objets de type entité, dont la durée
de vie est arbitraire.

(Il y a une exception, surtout avec des objets « agents »,
pour lesquels on aimerait d'une certain côté une sémantique de
valeur, mais qui doivent être polymorphiques. Dans ces cas-là,
si pour une raison quelconque, je n'ai pas de glaneur de
cellules, je me sers de boost::shared_ptr. Mais c'est loins
d'être un cas universel.)

?!? tu peux m'expliquer "traitement polymorphe" vs "traitement
générique", stp ?
peut-être penses-tu à ce que l'on nomme parfois un "polymorphisme
statique" (ie des classes templates).


Ça dépend du sens qu'on donne à polymorphisme, je parlais du
polymorphisme dynamique d'inclusion, qui introduit un coût à l'exéc ution
via l'utilisation de fonctions membres virtuelles et qui s'utilise via
des pointeurs ou références sur des bases.


Tu as mesuré, ce coût ? Au moins d'avoir des fonctions qui font
vraiment rien, je doute que la différence soit signifiante.
(Dans certains cas, évidemment, si, et je ne concevois pas de
classe équivalente de vector où l'operator[] soit virtuel.
Encore que... dans mes ArrayOf pré-standard, j'utilisais des
techniques de Barton et Nackmann pour avoir la virtuellité par
défaut, mais de pouvoir le circomventer quand je savais le type
et que les performances en souffraient.)

Je préfère l'usage des templates avec notamment le
policy-based design.


Tout dépend de ce qu'on fait : les templates permettent la
validation des prédicates sur le type, lors de la compilation,
par exemple, tandis qu'avec l'héritage et des fonctions
virtuelles, il faudrait compter plutôt sur une erreur lors de
l'exécution. En revanche, s'il s'agit réelement d'offrir
plusieurs façons de faire quelque chose -- ce qu'on entend par
le polymorphisme en général, le polymorphisme dynamique est
nettement plus souple. En fait, les deux possibilités servent à
deux choses différentes, et les cas où on peut se servir de
l'une ou de l'autre indifféremment sont assez rares.

Je te conseille fortement le livre de Barton et Nackman. C'est
daté, aujourd'hui, mais c'est encore l'un des rares livres qui
considèrent réelement les deux possibilités, en évaluant l'une
et l'autre. (D'après ce que j'ai entendu dire, c'est aussi le
cas du livre dont David Abraham est le co-auteur. Je n'ai pas
encore eu le temps de le lire, mais si je peux juger d'après ses
contributions dans les groupes de news anglophone, ça vaudrait
la peine.)

hein ??!!??

il me semble que Stepanov a présenté ce projet au comité
ANSI/ISO C++ entre fin 1993 et début 1994; à cette date,
vois-tu, je n'étais plus à l'école!


Quel rapport ?
Si tu veux développer en C++, il faut bien apprendre à un
moment ou à un autre. Que ce soit à l'école, en autodidacte,
ou dans un stage.


Apprendre quoi ? Pourvoir écrire une bonne classe de tableau ou
de chaîne, c'est une des choses la plus difficile qui soit en
C++. Il exige en plus certaines connaissances qui ne sont pas
vraiment d'une utilité générale, et qui ne servent que dans de
telles classes. Qu'on les enseigne dans une classe du C++
avancé, je veux bien, mais je ne vois aucun intérêt à ce que la
plupart des programmeurs C++ les étudient.

--
James Kanze GABI Software
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


Avatar
kanze
loufoque wrote:

[Je m'excuse, mais je ne peux pas résister:-)...]

Je vois pas trop l'intérêt d'avoir des choses persistantes en dehors
d'un programme.


Ton programme fait quelque chose, non ? Tu en jettes les
résultats ? Ou est-ce qu'ils persistent quelque part (au moins
dans ta têtes, parce que tu les as vu affichés sur l'écrans) ?

(Ceci dit, je ne comprends pas la polémique. Tu as simplement
dit que tu n'avais pas eu besoin de la mémoire partagée ; que
la communication par sockets a suffit pour tes applications. Je
ne vois pas de problème avec ça, dans la mesure où tu acceptes
que ce n'est pas une vérité universelle. Les sockets, la mémoire
partagée, et toute la reste ne sont que des outils, à utiliser à
bonne échéance, et non simplement parce qu'ils sont là. Les
sockets ont l'avantage -- énorme -- qu'ils fonctionnent même
quand les processus sont sur deux machines différentes ; la
mémoire partagée ne marche pas très bien quand le serveur est
sur un Sparc et le client sur une machine Windows. La mémoire
partagée a l'avantage qu'elle n'exige pas la sérialisation ; si
la quantité de données en question est importante, ça peut avoir
un effet non-négligeable sur les performances. Ce sont en fait
deux outils différents, pour résoudre des problèmes différents.
Et qu'à mon avis, quand il y a un choix, c'est plus souvent
entre un processus multi-thread, ou plusieurs processus avec de
la mémoire partagée, qu'entre sockets et mémoire partagée.)

--
James Kanze GABI Software
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

Avatar
Alain Gaillard


(En passant : pourquoi est-ce que parler de l'« ownership »
d'un objet me semble tout à fait naturel en anglais, mais que
l'utilisation du mot « propriété » dans le même contexte en
français ne me semble pas juste ?)


Je partage ton avis. Je préfère : détention de l'objet.



De même façon que dans le langage courant de l'informatique en
dehors de la communité C++, la généricité s'implémente souvent
au moyen de l'héritage.


Pas nécessairement. Pas dans les langages fonctionnels comme Haskell ou
Clean par exemple.


--
Alain

1 2 3 4 5