koala01 m'a doublé :aie:
Version imprimable
koala01 m'a doublé :aie:
Non, ca fait parti du contrat de std::vector :
ça se discute. Le contrat de std::vector spécifie vector::capacity et vector::reserve. En revanche, rien n'est imposé en terme de stratégie d'allocation du moment que les post conditions de ces 2 fonctions sont garanties (en gros, qu'il n'y as pas d'allocation avant autant d'ajout que retourne capacity et après reserve, capacity>=paramètre).Citation:
The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Cela fait partie du contrat, mais n'est-ce pas un contrat sur la manière dont les données sont stocké en interne ?
Je suis d'accord que, du moment qu'il y a un contrat assez précis, l’implémentation découle plus ou moins de ce dernier (on ne vas pas implémenter un conteneur avec accès en temps constant avec des listes chaînées), mais forcer l'implémentation à utiliser une manière de stocker les données plutôt qu'une autre, je trouve qu'on grattouille un peu les limites de l'encapsulation.
Pas vraiment...
N'oublie pas que "tableau", "pile", "file", "liste chainée" etc sont des concepts qui se rapportent à la gestion d'éléments plusriels que l'on retourve ou que l'on doit implémenter dans tous les langages.
Ces "concepts" sont clairement définis en termes de fonctionnalité et de complexité pour ce qui concerne l'ajout, la suppression et le parcours d'éléments: que tu travailles avec une liste simplement chainée en C, en C++, en Java ou en n'importe quel langage que tu puisse envisager, le but que tu recherche est de permettre l'insertion, l'ajout et la suppression en temps constant et de favoriser l'accès séquentiel aux différents élément.
Tu t'astreint donc à un contrat garantissant ces complexités, ce qui, naturellement, amènera à une implémentation sensiblement similaire quel que soit le langage utilisé.
Il est donc tout à fait logique que la norme, tout en laissant l'implémentation libre, explicite clairement les contrats qui devront être respectés pour les différents types de colletions, vu que ces contrats font partie de ce que l'on attend des concepts eux-même ;)
Bonsoir,
le problème initial qui a généré toute cette discussion est de savoir comment calculer la distance entre un point et un segment. A mon sens, la meilleure réponse possible a été donnée pratiquement juste après : un lien vers un site expliquant comment faire et donnant une formule facile à implémenter. Ecrire sa propre fonction calculant cette distance ne relève pas du tout syndrome NIH. La "roue" existe, on l'a donnée, il reste à l'implémenter. Conseiller une grosse bibliothèque (boost, geos, ou toute autre) pour faire cela, c'est vraiment prendre un marteau pour écraser une mouche pour reprendre une expression déjà utilisée dans cette discussion. Je ne vois même pas où est le débat sur ce point. En fait, la question initiale ne relève même pas du C++ : elle n'a pas été postée au bon endroit.
En revanche, c'est une bonne chose de mentionner que ces bibliothèques existent et de montrer qu'il peut être très simple d'y avoir recours : c'est ce que 3DArchi a pris le temps de faire en fournissant un exemple d'utilisation pour le problème de calcul de distance concerné. Ensuite, c'est à la personne qui est venu poser sa question de déterminer si elle va juste avoir besoin de calculer la distance d'un point à un segment ou si elle va en fait avoir besoin d'une multitude de fonctions géométriques du même genre. Dans ce dernier cas, il y a effectivement syndrome NIH parce qu'elle va passer plus de temps à tenter d'écrire ces fonctions par elle-même plutôt que de se familiariser avec une bibliothèque (installation comprise), le tout pour un résultat qui risque fortement d'être de moins bonne qualité que ce que propose telle ou telle bibliothèque (réinvention de la roue carrée).
Pour ce qui est du syndrome NIH en entreprise, c'est un peu plus délicat. Cela dépend de beaucoup de facteurs techniques/humains et il me semble difficile de faire des généralités sur ce point. Je précise au passage que ce n'est pas mieux dans le secteur public (CNRS, ...) qu'ailleurs. Joel F travaille dans un laboratoire d'informatique mais je suis certain qu'il sait aussi bien que moi que dans d'autres spécialités, les connaissances en informatique sont... disons plus légères.
En ce qui me concerne, je suis un utilisateur de ce forum, pas du tout un expert du c++. J'apprends énormément de choses ici que je n'ai pas vues pendant mes études. Ceci dit, maintenant que je commence à bien connaître le forum, je peux tout de même formuler une critique importante (d'utilisateur). Quasi-systématiquement, lorsque je pose une question, on me renvoie vers boost, même si je précise dans mon intitulé que ce n'est pas le but recherché. Il y a des personnes qui développent dans boost et je peux comprendre qu'elles cherchent à promouvoir cette bibliothèque mais ce n'est pas toujours dans l'intérêt de la personne qui a posté une question. Je distinguerai deux types de réponses :
1. utilise boost.geometry c'est très bien, voici les avantages/inconvénients, je te donne un petit exemple pour que tu puisses démarrer et te donner envie d'utiliser cette bibliothèque
2. boost.geometry
La réponse 1 est parfaite, on y apprend des choses, c'est ce qu'a fait 3DArchi pour ne pas le citer. Je ne citerai pas ceux qui ont tendance à faire la réponse 2 mais parfois je me demande s'ils savent à quel point leur réponse ne sert (pratiquement) à rien. Premièrement, ce serait mieux de faire une phrase (majuscule + point), introduite par quelques salutations. Deuxièmement, pourquoi boost? Parce que c'est mieux ou parce que vous participez au développement?
Il faut admettre qu'il y a des personnes qui viennent ici pour apprendre (à mon avis la majorité mais je peux me tromper) et qui ont besoin de faire quelques roues carrées pour progresser.
Peut etre ne l'as tu pas remarqué, mais la modération a bien fait sont travail et a scindé la discussion...
Nous sommes ici dans une nouvelle discussion qui, justement, ouvre le débat sur le NIH, pour, justement, éviter de "pourrir" la celle d'origine avec des considérations qui n'ont rien à voir avec le problème du PO ;)
@koala : je suis désolé mais c'est loin d'être clair étant donné que le lien vers l'ancienne discussion est donné dans le premier message et qu'il y est mentionné que la présente discussion y fait suite.
@koala : à quoi cela sert-il de m'indiquer l'origine du débat si je ne peux en parler? Ou alors je n'ai pas compris ton intervention concernant mes remarques?
Non, ce qui existe a ce point, c'est le plan de la roue.
Boost ou geos, c'est le choix entre Michelin et Bridgestone.
Tu coules la resine de tes pneux toi ? Moi, non.
Si tu savais, tu ferais comme moi, tu pleurerais du sang
On pousse rien. Si boost reviens tout le temps ou POCO ou w/e, c'est que l'implantation est la, tester et valider. Et je repete apprendre a se servir de composants logiciels, c'est 101 du developement,
Non, non, il s'agit bien de la roue. Comme je l'écrivais, la question n'a rien à voir avec le c++ et aurait dû être postée dans un autre forum (algorithmes).
En ce qui concerne le fait de réinventer la roue proprement dit, on pourrait faire ce reproche à boost comme à beaucoup d'autres bibliothèques.
Je ne connais pas cette expression et le contexte ne me permet d'en déduire le sens.
Je ne reproche pas de conseiller boost ou tout autre bibliothèque. Je critique la manière dont cela est fait parfois. Et je suis en parfait accord avec ta seconde phrase même si implémenter quelques fonctions élémentaires par soi-même fait également parti de l'apprentissage. L'un ne doit pas empêcher l'autre.
Bonjour,
@aleph69: merci pour tes remarques intéressantes. J'en comprends la remarque implicite. Je me souviens avoir été dérouté lorsque j'ai commencé à fréquenter ce forum et que l'on me répondait par d'obscurs sigles... comme NIH :aie:
Je pense qu'il est aussi important de comprendre que la première bonne solution à un problème est : "existe-t-il une bibliothèque qui fait déjà ça ?". Ca devrait être le premier (ou presque) cours de programmation.
La question était-elle posée au bon endroit ? J'ai tendance à penser que si elle l'a été sur le forum C++, c'est qu'une solution mathématique n'était pas l'objectif premier mais bien une implémentation C++. A partir de là, il me semble que diriger vers une bibliothèque est assez pertinent.
Un marteau pour écraser une mouche ? Depuis le début de cette question, je pense et je maintiens que Boost.Geometry est de loin une solution triviale : un téléchargement, un dezip (certes très gros, mais pas plus que mon IDE), un #include et c'est tout ! Je suis curieux de savoir combien de temps on passe à faire sa propre fonction de calcul ? Entre se demander quel type pour les points, les segments, puis implémenter le calcul, se rendre compte qu'on a fait un ou deux bugs, les corriger. Si on est bien, on a un petit document de design, un jeu de test U, et soyons fou, une revue par un pair et pourquoi pas un outil d'analyse statique. Il est où le marteau ;) ?
Dans le cas général, oui. Mais je rejoins Aleph69, c'est toujours bon de donner une lib et encore mieux de donner un exemple d'utilisation, mais dans l'absolue ça ne répond pas à la question initial. Cela ne peut venir qu'en complément.Citation:
Je pense qu'il est aussi important de comprendre que la première bonne solution à un problème est : "existe-t-il une bibliothèque qui fait déjà ça ?".
On ne sais jamais à quels contraintes est soumis la personne qui pose la question. Peut-être utilise-t-elle déjà une lib maison auquel il manque quelques fonction. Peut-être son chef refuse d'intégrer une nouvelle lib juste pour ça (pour des raisons plus ou moins justifiés). Peut être est-ce un exercice de TD où elle doit jutement réinventer la roue. Peut être n'a-t-elle tout simplement pas envie d'utiliser une lib et qu'elle souhaite la recoder elle-même pour s'amuser. C'est bon des fois d'aller au McDo manger de la m*** :ccool:
Bref, il y a une multitude de cas particulier, certes minoritaire, qui font qu'utiliser une lib n'est pas forcement la réponse souhaitée.
J'ai l'impression que l'on est d'accord sur le principal, sauf sur l'ordre dans lequel les choses "doivent" se faire...
Ce que disent 3D, joel et tant d'autres (et à quoi je souscris, d'ailleurs), c'est que le plus facile, c'est de prendre une roue "toute faite", pour éviter de nous retrouver avec une roue carrée, mal centrée ou ovoide, et pour éviter de s'attaquer à une théorie dont la personne n'a sans doute que faire, et que ce devrait être la première solution proposée.
Puis, si, pour une raison X, Y ou Z dont il ne nous appartient pas de juger la pertinence, la roue toute faite ne convient pas, il sera toujours temps de nous ateler à la création d'une roue "maison".
Mais cela passera par un tas de théorie, dont une partie sera sans doute fort éloignée du problème (mais nécessaire pour la compréhension) et pour un résultat pouvant présenter quelques lacunes
C'est exactement la même chose que de répondre FAQ ou STFW. Mais en un chouilla plus constructif (que STFW) vu que l'on a déjà donné la piste.
Ceux qui répondent n'ont pas forcément de le temps pour rédiger une réponse de qualité. Ils ne sont pas là pour donner des solutions NIHiennes clé en main (pour exactement les mêmes raisons que l'on ne répond pas aux exo en donnant les solutions clés en main) ; sans parler que les snippets de codes donnés dans les forums devraient être sous droit d'auteur et non dans le domaine public si on reste strict, ce qui poserait normalement des problèmes pour les intégrer dans des produits libres, open-source ou propriétaires.
De plus, ce n'est pas parce que l'on connait le nom d'une lib qui répond au besoin que l'on va savoir comment l'utiliser. Pourquoi serait-ce au bénévole qui répond à lire la doc d'un truc dont il n'a pas forcément l'utilité ou pour lequel il n'a pas la curiosité d'en savoir plus ? Devrait-il ne pas donner la piste de réponse parce qu'il n'a pas envie/temps de faire le boulot de l'OP pour voir comment ça marche exactement ?
NB: bien sûr après il y a maintes façons de répondre pour dire "regarde le COTS machin, il résout ton problème normalement".
<on n'est pas vendredi pourtant...>
Non, pas perdus. Mais le coup de gueule est normal. Quand on passe d'un éditeur de code sources à un truc aussi évolué que notepad pour éditer son texte, c'est très agaçant.
Définir un projet pour compiler un malheureux fichier c'est idiot aussi, mais bon, c'est comme ça.
</>
Ça peut être plus que ça.
Je crois me souvenir que dans Effective C++, la taille des objets String, pour une chaîne vide varie d'un facteur 1 à 4 selon l'implémentation.
Quand tu dois interagir avec une bibliothèque C, c'est loin d'être un détail.
Il me semble avoir lu quelque part que ce n'est plus vrai, mais ça mériterai vérification.Citation:
Ça peut être plus que ça.
Je crois me souvenir que dans Effective C++, la taille des objets String, pour une chaîne vide varie d'un facteur 1 à 4 selon l'implémentation.
@3DArchi, tu l'appelles depuis VC++ ? En passant par les hotkeys usuelles ?
libstdc++ de GNU: COW
STLport: string concatainator (par expression template) -> interface non conforme au standard (même si c'est probablement l'implémentation la plus intelligente); probablement du COW derrière, j'avoue avoir oublié.
dinkumware: small-string optimization
OK, c'est bien ça. Cela ne se fait pas depuis VC++, mais depuis DOS, voire vim, comme d'habitude...
Voyons messieux, il y a longtemps que ce n'est plus DOS derrière, c'est juste une invite de comande :aie:
Les papys, ils parlent encore en DOS et en anciens francs :mouarf:
@Luc : à la limite, rien ne t'empêche de rajouter dans "Tools" un appel vers cl pour ne pas avoir à faire de projet (ou un bat s'il y a d'autres flags à positionner)
Justement, ce que je voulait dire au début (mais je me suis un peu perdu en route), c'est que le principe de l'encapsulation "parfaite", la grosse boite noir où l’intérieur est totalement masqué, ne peut pas toujours marcher.
Malgré que les vecor soit une manière de s'affranchir de tout ce qui est gestion mémoire, pointeurs, etc... arrive un moment où on doit bien faire avec et où il faut un petit hublot à la boite noir (en l'imposant dans la norme si nécessaire). Malgré une interface haut niveau qui nous simplifie le travail, savoir ce qu'il se passe à plus bas niveau est parfois indispensable.
Après, il y a peut être un problème de vocabulaire quant au terme "implémentation". On peu considérer que, si c'est dans la norme, alors ce n'est pas de l'implémentation (car justement, on ne peut pas l'implémenter comme on le souhaite). Mais on peut aussi considérer (comme moi) que l'implémentation concerne tout ce qui n'est pas purement "théorique", tout ce qui relève de considération bassement matérialiste comme le fait que nos machines n'ont pas une mémoire infinie.
Non (enfin, c'est un mauvais exemple). La contiguité des éléments d'un conteneur de type vector<T> est garantie par la norme C++. Si cette garantie était implicite dans le standard de 98, elle est maintenant explicite :
Emphasis is mine, comme dirais les habitants de la Grosse Pomme.Citation:
Envoyé par n3242, 23.3.6.1§1
L'implémentation, c'est la mise en oeuvre d'une définition dans les limites offertes par le système cible.Citation:
Mais on peut aussi considérer (comme moi) que l'implémentation concerne tout ce qui n'est pas purement "théorique", tout ce qui relève de considération bassement matérialiste comme le fait que nos machines n'ont pas une mémoire infinie.
Non, ce n'est pas sale, c'est juste hors cadre : la norme (C++) définit un contrat (interfaces, complexité des algorithmes, entrées et sortie des fonctions, ABI, etc) ; l'implémentation doit respecter ce contrat, mais en dehors de ça, elle est libre.
Du coup, elle ne parle pas d'implémentation - parce que ça n'est pas son rôle, pas parce que c'est sale. D'autres normes définissent non seulement une interface mais aussi l'implémentation liée à cette interface - généralement sous la forme d'algorithmes.
La raison pour laquelle parler d'implémentation est hors scope du standard C++ est simple : en standardisant une manière d'implémenter, on s'interdit toute évolution future de cette implémentation tant que le standard ne change pas. Hors, une optimisation particulière peut rendre obsolète une implémentation très rapidement (tant de choses ont été découverte dans le C++ après la standardisation de celui-ci).
Non, le fait de préciser que les éléments d'un vecteur sont contigus fait parti du contrat. La norme ne précise pas le moyen que doit utiliser le vendeur de compilateur pour arriver à ce résultat, juste que la relation &v[n] == &v[0] + n doit être vraie (dans les limites des conditions posées). Nous n'imaginons à l'heure actuelle qu'un moyen unique d'arriver à cette solution - celle d'allouer un bloc de mémoire contigu. Mais nous manquons un peu d'imagination.
Personnellement, j'imagine sans peine un système proposant un accès à une MMU virtuelle permettant de concaténer dans un superbloc de mémoire virtuelle des blocs de mémoire alloués au préalable et non contigus. Ca permettrait d'implémenter l'élargissement d'un std::vector<> sans faire une seule copie (j'alloue un bloc supplémentaire, et je dis à ma MMU virtuelle que ce bloc est contigu à mon superbloc).
(ce qui est étonnant, c'est que je suis en train d'écrire un article qui parle de notre manière de raisonner par inférence, et que tu as utiliser cette manière de raisonner à l'instant : ce n'est pas parce qu'on précise que les éléments d'un vecteur sont contigus qu'il n'existe qu'une seule manière d'arriver à ce résultat, même si on n'arrive pas nécessairement à imaginer une autre manière de le faire).
Cette implémentation n'est a priori pas réalisable car std::vector doit utiliser l'allocateur fourni, qui ne permet pas de mapper des pages mémoire.Citation:
Personnellement, j'imagine sans peine un système proposant un accès à une MMU virtuelle permettant de concaténer dans un superbloc de mémoire virtuelle des blocs de mémoire alloués au préalable et non contigus. Ca permettrait d'implémenter l'élargissement d'un std::vector<> sans faire une seule copie (j'alloue un bloc supplémentaire, et je dis à ma MMU virtuelle que ce bloc est contigu à mon superbloc).
C'est de toute façon le rôle de l'allocateur de jouer avec la mémoire. Une implémentation particulière de l'allocateur par défaut peut, si besoin, effectuer l'opération que j'ai décrit en utilisant le paramètre hint - il est là pour ça.
Je ne vais pas prendre ce soir le temps de relire toutes les parties nécessaires du standard, mais à mon humble avis, celui-ci offre des possibilités pour implémenter un système de gestion de la mémoire qui est plus intéressant (pour l'embarqué, notamment) que les implémentation génériques qu'on utilise à l'heure actuelle.
la maniere dont tu presentais la chose semblait donner cette responsabilité a vector.
Rien ne t'empeche de faire std::vector<T, mmu_allcoator<T> > effectivement.
Ce n'est pas possible. Allocator aurait besoin de supporter l'agrandissement en-place pour que ce le soit.
Tout ce que permet l'allocateur, c'est d'allouer un objet et de donner le pointeur vers celui-ci ou de libérer des objets précédemment alloués. Il n'y a aucun moyen pour l'allocateur de savoir qu'il peut mapper un segment de mémoire libre à la fin d'un bloc pour l'étendre.
Ce que fait vector, quand il agrandit, c'est allouer un bloc plus gros et recopier (ou déplacer en C++0x). À aucun moment il y a la moindre opportunité de faire quelque chose d'intelligent. Il n'y a pas de fonction "alloue à cette adresse" dans l'allocateur, et une telle abstraction n'aurait d'ailleurs pas de sens car elle nécessiterait forcément une MMU.
Des extensions pour rajouter l'agrandissement en-place dans les allocateurs ont été suggérées, cependant.
Si, en utilisant le paramètre hint de la fonction qui effectue l'allocation. Ce paramètre, tel que le spécifie la norme, peut être utilisé pour passer un pointeur - par exemple l'adresse virtuelle du segment de mémoire déjà alloué.
La fonction d'allocation est définie par :
Avec le texte :Code:pointer allocate(size_type, allocator<void>::const_pointer hint = 0);
Citation:
hint either 0 or previously obtained from member allocate and not yet passed to member deallocate. The value hint may be used by an implementation to help improve performance.
Remark: the storage is obtained by calling ::operator new(std::size_t), but it is unspecified when or how often this function is called. The use of hint is unspecified, but intended as an aid to locality if an implementation so desire.
Imaginons que tu décides de donner comme sémantique à ton allocateur de faire l'allocation à l'adresse passée dans hint (ce qui n'est absolument pas pour ça que le hint existe, il existe pour accélérer la recherche d'un élément libre dans un arbre éventuel qui servirait à gérer le tas mémoire).
Il n'empêche que vector ne peut toujours pas utiliser ça pour faire de l'extension en-place.
Je comprends ton point de vue. Ceci dit, je ne parle pas de faire de l'extension in-place dans le vecteur de manière générale, je parle d'une architecture matérielle spécifique où un telle option pourrait être implémentée, sans pour autant contredire le standard. C'était une manière de rappeler que le standard ne force aucune implémentation, même lorsqu'il semble qu'il le fasse.
Après, tu es libre de faire partir la discussion ou tu veux - elle est déjà suffisamment éloignée du port d'origine :)