Certes, après coup, c'est toujours facile. Mais là, c'est franchement pas sérieux.
D'autant que le leaf ... ça veut dire "salut, je ne viendrais pas taper dans une autre unité de compilation que la mienne", ce qui objectivement est vrai.
Mais ca ne sert pas qu'a seulement le dire, n'est ce pas ? Il y a des conséquences derrière, en particulier des possibilité d'optimisation. Sinon, ce n'était pas la peine de mettre en place cet attribut.
Si les problèmes de multi-threading étaient simples, surtout à un niveau aussi bas, ça se saurait.
C'est justement ce que je voulais souligner : comme ce n'est pas un sujet trivial, il aurait peut etre été judicieux d'envisager toute les conséquences avant d'apporter une modification a quelque chose qui fonctionnait correctement jusqu'à présent.
Ahem.... donc les mainteneurs de la glibc auraient ajouté au fonctions pthread_mutex_lock/unlock un attribut qui dit au compilo "salut, nous sommes des fonctions inoffensives, tu peux nous optimiser" ?
Ils avaient abusé de substances qui font rire, ou bien ils sont complètements crétins ?
Chez Numéricable, pendant longtemps, un seul PC avait droit à avoir internet. Le 2e était payant
Chez Noos aussi, il y avait ce genre de restriction. Mais bon, comme ils etaient incapable de repérer le 2eme PC (ou plus), fallait vraiment être nouille pour leur dire...
Si tu veux de la qualité, tu achète un original, pas la copie.
Ca c'est vrai dans le cas général, mais parfois tu peux avoir une copie de qualité égale à l'original, même pour des sacs de luxe.
Grosso-modo, le commanditaire (la marque) sous-traite à plusieurs atelier la fabrication de son sac, avec comme contrainte que celui qui livre la commande en premier sera payé, et les autres, non seulement ils ne toucheront pas d'argent, mais en plus ils se débrouilleront avec le stock. Evidemment, ce surplus est écoulé vers le marché de la contrefaçon (la description complète dans Gomorra).
Dans ce schéma, la seule différence entre un original et une copie, c'est la seule volonté de la marque, rien ne peut physiquement les différencier, et jusqu'au dernier moment les deux produits ont le même statut, ce sont des originaux.
N'hesite plus, je ne comprends vraiment pas, en particulier le sens que tu donnes au verbe "allouer". Mais, ce n'est pas grave, tu as raison et j'ai tord (et je m'en contretape).
soit tu permet de changer la valeur du pointeur encapsulé, et dans ce cas il vaux mieux que ton compteur soit alloué des le début sinon tu vas avoir du mal à le rajouter plus tard ;
Eh bien visiblement, les auteurs de boost::shared_ptr n'ont pas fait ce choix, le compteur n'est pas alloué dans le cas du constructeur par défaut, et pourtant on peut changer la valeur du pointeur encapsulé par affectation d'un autre shared_ptr, ou appel de la fonction reset(T*).
C'est l'absence d'allocation qui permet de garantir que le constructeur par défaut ne lance jamais d'exception (nothrow guarantee), et c'est important pour l'implementation de la fonction membre reset() qui utilise ce constructeur (cf la documentation).
Oui, effectivement, il y a allocation de deux pointeurs sur la pile (pour une définition étendue de l'allocation). Mais bon, c'est la pile quoi, y'a pas besoin de GC ...
Un smart pointer est un objet qui encapsule un pointeur, il y a donc bien une allocation de l'objet qui encapsule. Tu peux mettre ce que tu veux comme pointeur dedans, qu'il soit valide ou invalide ne change rien au fais qu'il y a bien allocation d'une coquille pour stocker le pointeur et son compteur de références.
La derniere fois que j'ai regardé l'implementation de boost::shared_ptr, j'y ai vu... qu'il n'y a pas de telle coquille. Le shared_ptr possède deux membres, un pointeur vers le compteur de référence, et un pointeur vers l'objet partagé (oui, les deux ne sont pas co-localisés, c'est un design possible, il y avait un papier sur les performances qui trainait sur le site, bref...)
Et avec ce modèle, on n'est pas obligé d'allouer le compteur dans le constructeur par défaut, parce que cela ne sert a rien.
Désolé, jne n'avais pas cherché a comprendre ce que tu voulais dire, mais d'autre s'en sont chargés dans les commentaires an dessous. Maintenant je vois, et je me dis qu'un bon design d'utilisation des references partagées serait plus efficace que la solution a compteurs global/local. Mais mon, c'est que mon avis...
Relis attentivement l'exemple de Thomas. Si tu ne comprends pas pourquoi il faut un comptage de référence atomique, tu devrais t'abstenir de faire de la programmation multi-thread, tu vas au devant de sérieux problèmes.
il faut remplacer les .begin et .end par .cbegin et .cend, j'imagine pour que l'inférence de type produise un const_iterator au lieu d'un iterator, c'est logique mais comme cela nécessite de changer les habitudes des programmeurs, ça fera probablement une "erreur" (mineure) commune de plus.
Et on a maintenant deux fonctions .begin et .cbegin qui retournent un const_iterator (pareil pour end), pour ne pas casser le code qui utilisait .begin sur un vector const ... c'est moche.
20 lignes ? J'aimerais bcp voir un pool en 20 lignes qui marche et qui est efficace (temps d'allocation, support multithread,...)
Oui, 20 lignes, c'est nettement suffisant pour un pool simple, sans multi-thread (tu rajoutes des contraintes quand ça t'arrange). Pour un exemple, demande à Herb, il te montrera.
Un pool à multiples blocs, typé et réutilisable, c'est grosso-modo 20 lignes de code, sans aucun impact sur le reste si on surcharge new/delete dans la structure bob. Ou est le problème ?
J'ai un peu de mal à cerner le genre de programme auquel tu fais référence : on a besoin d'un maximum de performances (on descend jusqu'au lignes de cache), mais d'un autre coté on alloue de nombreux objets de petite taille, avec cycle de vie court (la performance des ctor/dtor a été évoquée), et on ne peut pas faire de pré-allocation massive parce qu'il faut aussi réduire l'empreinte mémoire globale...
Ca depend du cas comme pour tout, si par defaut ton vecteur a une taille allouee de 10 objets (parce que dans le cas usuel ou le vecteur contient quelque chose il en a 10), ton constructeur va faire une allocation a chaque fois par exemple.
Gni ? L'implémentation de std::vector n'est pas obligée de faire une préallocation si on ne donne pas de capacité initiale. Si le constructeur par défaut le fait quand même, c'est un problème de qualité d'implémentation de std::vector.
Si dans ton cas particulier le vector contient généralement 10 elements, rien ne t'empeche de faire un reserve(10) avant la premiere insertion, que le vecteur soit alloué dynamiquement ou non.
L'allocateur standard dans Windows a tout un tas de features pour eviter qu'un buffer overflow dans la heap ne se transforme en vulnerabilite (...), je ne connais a peu pres aucun allocateur 'custom' qui a ces features.
Un simple pool de char[sizeof bob] obtenues via l'allocateur est suffisant.
a) J'evites le cout du constructeur / destructeur si le vecteur n'est pas utilise
Quel est le cout d'un constructeur / destructeur pour un vecteur vide ? Si le cycle de vie de la structure est un probleme de performance, ca ne viendrait pas plutot de l'allocateur ?
En ce qui concerne la taille de la structure et les performances d'un allocateur "standard" par bloc, cela n'est pertinent que si tu alloue tes structures unitairement avec cet allocateur (un gros tableau de structures n'est pas concerné).Si tu as vraiment des problèmes de performance liées a ton allocateur, pourquoi ne pas en prendre un autre, puisque le langage le permet facilement ?
Ah, oui, je comprends mieux. Donc pour gagner en performance, tu rajoute une indirection supplémentaire, et tu parsème ton code de tests if (MonVecteur != 0), c'est bien ça ?
La question portait sur l'allocation dynamique d'un std::vector<T> et la manipulation de pointeurs sur std::vector<T> ensuite, et dans ton exemple tu parles d'un tableau T[], ce n'est pas le meme besoin.
Maintenant, pour l'occupation memoire, le tableau de base, c'est au moins un pointeur, mais tu as aussi besoin de sa capacité (taille allouée), et du nombre d'éléménts présents (taille utilisée). Au final, c'est la même empreinte mémoire, sauf si la capacité et la longueur sont fixes. Mais dans ce cas, pourquoi ne pas utiliser std::array<T> ?
Bref, ca ne sert a rien d'allouer dynamiquement un std::vector<T>.
Tu viens de montrer qu'il est techniquement possible de dériver de std::vector, c'est a dire que le compilateur ne génère pas de diagnostic. Le problème, c'est que le compilateur ne va pas t'avertir des dangers potentiels a l'utilisation.
Et pourtant, dans la fonction run(), c'est bien l'instance de MyVector qui est utillisée, n'est-ce pas ? Pourquoi le comportement du programme a-t'il changé ?
Tu auras aussi des résultats comiques si tu ajoute un destructeur spécifique a MyVector et que tu manipules tes instances par l'intermédiaire de pointeur sur sdt::vector...
Les containers de la STL ne sont pas conçus pour êtres dérivés en public, mais il n'y a pas de garde fou, comme d'habitude.
[^] # Re: En clair
Posté par shbrol . En réponse au journal Vente liée : comment se tirer soi-même une balle dans le pied. Évalué à 3.
Oui, chez moi aussi ca marche, sur un systeme 32bits avec 1Go RAM (et autant de swap). Etonnant, non ?
Par contre, un calloc(5000000,1000) échoue. Tu vois pourquoi ?
[^] # Re: Un peu d'explications sur le bug introduit
Posté par shbrol . En réponse au journal Merci aux développeurs de la GNU libc !. Évalué à 4.
Certes, après coup, c'est toujours facile. Mais là, c'est franchement pas sérieux.
Mais ca ne sert pas qu'a seulement le dire, n'est ce pas ? Il y a des conséquences derrière, en particulier des possibilité d'optimisation. Sinon, ce n'était pas la peine de mettre en place cet attribut.
C'est justement ce que je voulais souligner : comme ce n'est pas un sujet trivial, il aurait peut etre été judicieux d'envisager toute les conséquences avant d'apporter une modification a quelque chose qui fonctionnait correctement jusqu'à présent.
[^] # Re: Un peu d'explications sur le bug introduit
Posté par shbrol . En réponse au journal Merci aux développeurs de la GNU libc !. Évalué à 6.
Ahem.... donc les mainteneurs de la glibc auraient ajouté au fonctions pthread_mutex_lock/unlock un attribut qui dit au compilo "salut, nous sommes des fonctions inoffensives, tu peux nous optimiser" ?
Ils avaient abusé de substances qui font rire, ou bien ils sont complètements crétins ?
[^] # Re: Y a-t-il eu un jugement ?
Posté par shbrol . En réponse à la dépêche Free publie enfin ses patchs sur les logiciels libres. Évalué à 2.
Chez Noos aussi, il y avait ce genre de restriction. Mais bon, comme ils etaient incapable de repérer le 2eme PC (ou plus), fallait vraiment être nouille pour leur dire...
[^] # Re: Interessant
Posté par shbrol . En réponse au journal Répression et peines de prison. Évalué à 5.
Ca c'est vrai dans le cas général, mais parfois tu peux avoir une copie de qualité égale à l'original, même pour des sacs de luxe.
Grosso-modo, le commanditaire (la marque) sous-traite à plusieurs atelier la fabrication de son sac, avec comme contrainte que celui qui livre la commande en premier sera payé, et les autres, non seulement ils ne toucheront pas d'argent, mais en plus ils se débrouilleront avec le stock. Evidemment, ce surplus est écoulé vers le marché de la contrefaçon (la description complète dans Gomorra).
Dans ce schéma, la seule différence entre un original et une copie, c'est la seule volonté de la marque, rien ne peut physiquement les différencier, et jusqu'au dernier moment les deux produits ont le même statut, ce sont des originaux.
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 2.
Oui, tu as raison, les deux ont le meme objectif. Il n'y a pas plus de différence qu'entre FILE* et std::iostream.
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
N'hesite plus, je ne comprends vraiment pas, en particulier le sens que tu donnes au verbe "allouer". Mais, ce n'est pas grave, tu as raison et j'ai tord (et je m'en contretape).
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
Eh bien visiblement, les auteurs de boost::shared_ptr n'ont pas fait ce choix, le compteur n'est pas alloué dans le cas du constructeur par défaut, et pourtant on peut changer la valeur du pointeur encapsulé par affectation d'un autre shared_ptr, ou appel de la fonction reset(T*).
C'est l'absence d'allocation qui permet de garantir que le constructeur par défaut ne lance jamais d'exception (nothrow guarantee), et c'est important pour l'implementation de la fonction membre reset() qui utilise ce constructeur (cf la documentation).
Et on verifie tout ca dans le source :
http://www.boost.org/doc/libs/1_47_0/boost/smart_ptr/shared_ptr.hpp
http://www.boost.org/doc/libs/1_47_0/boost/smart_ptr/detail/shared_count.hpp
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
Oui, effectivement, il y a allocation de deux pointeurs sur la pile (pour une définition étendue de l'allocation). Mais bon, c'est la pile quoi, y'a pas besoin de GC ...
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
La derniere fois que j'ai regardé l'implementation de boost::shared_ptr, j'y ai vu... qu'il n'y a pas de telle coquille. Le shared_ptr possède deux membres, un pointeur vers le compteur de référence, et un pointeur vers l'objet partagé (oui, les deux ne sont pas co-localisés, c'est un design possible, il y avait un papier sur les performances qui trainait sur le site, bref...)
Et avec ce modèle, on n'est pas obligé d'allouer le compteur dans le constructeur par défaut, parce que cela ne sert a rien.
[^] # Re: Gouverner, c'est prévoir. Limiter internet, c'est régresser.
Posté par shbrol . En réponse au journal Horreur, enfer et damnation: Fin de l'illimité. Évalué à 8.
Recherche sur google.fr, avec les mots "yacht tva". Le premier lien contient la phrase :
donc il semblerait que le riche, lorsqu'il s'achète un yacht, a la possibilité de ne pas payer la TVA en passant par un intermédiaire spécialisé.
Par contre, je n'ai pas trouvé le même genre de service pour les paquets de pâtes...
[^] # Re: Gouverner, c'est prévoir. Limiter internet, c'est régresser.
Posté par shbrol . En réponse au journal Horreur, enfer et damnation: Fin de l'illimité. Évalué à 3.
Si tu place ton épargne sur un support qui se casse la figure, il y a une certaine partie qui ne sera pas soumise a la TVA.
[^] # Re: Gouverner, c'est prévoir. Limiter internet, c'est régresser.
Posté par shbrol . En réponse au journal Horreur, enfer et damnation: Fin de l'illimité. Évalué à 2.
Source ?
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
Désolé, jne n'avais pas cherché a comprendre ce que tu voulais dire, mais d'autre s'en sont chargés dans les commentaires an dessous. Maintenant je vois, et je me dis qu'un bon design d'utilisation des references partagées serait plus efficace que la solution a compteurs global/local. Mais mon, c'est que mon avis...
[^] # Re: templates variadiques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
Relis attentivement l'exemple de Thomas. Si tu ne comprends pas pourquoi il faut un comptage de référence atomique, tu devrais t'abstenir de faire de la programmation multi-thread, tu vas au devant de sérieux problèmes.
[^] # Re: Quelque petite remarques
Posté par shbrol . En réponse à la dépêche Le standard C++0x a enfin été voté. Évalué à 1.
Et on a maintenant deux fonctions .begin et .cbegin qui retournent un const_iterator (pareil pour end), pour ne pas casser le code qui utilisait .begin sur un vector const ... c'est moche.
[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 2.
Oui, 20 lignes, c'est nettement suffisant pour un pool simple, sans multi-thread (tu rajoutes des contraintes quand ça t'arrange). Pour un exemple, demande à Herb, il te montrera.
[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 1.
Un pool à multiples blocs, typé et réutilisable, c'est grosso-modo 20 lignes de code, sans aucun impact sur le reste si on surcharge new/delete dans la structure
bob
. Ou est le problème ?J'ai un peu de mal à cerner le genre de programme auquel tu fais référence : on a besoin d'un maximum de performances (on descend jusqu'au lignes de cache), mais d'un autre coté on alloue de nombreux objets de petite taille, avec cycle de vie court (la performance des ctor/dtor a été évoquée), et on ne peut pas faire de pré-allocation massive parce qu'il faut aussi réduire l'empreinte mémoire globale...
Un exemple concret serait le bienvenu.
[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 2.
Gni ? L'implémentation de std::vector n'est pas obligée de faire une préallocation si on ne donne pas de capacité initiale. Si le constructeur par défaut le fait quand même, c'est un problème de qualité d'implémentation de std::vector.
Si dans ton cas particulier le vector contient généralement 10 elements, rien ne t'empeche de faire un
reserve(10)
avant la premiere insertion, que le vecteur soit alloué dynamiquement ou non.Un simple pool de char[sizeof bob] obtenues via l'allocateur est suffisant.
[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 1.
Quel est le cout d'un constructeur / destructeur pour un vecteur vide ? Si le cycle de vie de la structure est un probleme de performance, ca ne viendrait pas plutot de l'allocateur ?
En ce qui concerne la taille de la structure et les performances d'un allocateur "standard" par bloc, cela n'est pertinent que si tu alloue tes structures unitairement avec cet allocateur (un gros tableau de structures n'est pas concerné).Si tu as vraiment des problèmes de performance liées a ton allocateur, pourquoi ne pas en prendre un autre, puisque le langage le permet facilement ?
[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 3.
Ah, oui, je comprends mieux. Donc pour gagner en performance, tu rajoute une indirection supplémentaire, et tu parsème ton code de tests
if (MonVecteur != 0)
, c'est bien ça ?[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 1.
La question portait sur l'allocation dynamique d'un
std::vector<T>
et la manipulation de pointeurs surstd::vector<T>
ensuite, et dans ton exemple tu parles d'un tableauT[]
, ce n'est pas le meme besoin.Maintenant, pour l'occupation memoire, le tableau de base, c'est au moins un pointeur, mais tu as aussi besoin de sa capacité (taille allouée), et du nombre d'éléménts présents (taille utilisée). Au final, c'est la même empreinte mémoire, sauf si la capacité et la longueur sont fixes. Mais dans ce cas, pourquoi ne pas utiliser
std::array<T>
?Bref, ca ne sert a rien d'allouer dynamiquement un
std::vector<T>
.[^] # Re: works for me
Posté par shbrol . En réponse à la dépêche Naissance d'un géant : Java. Évalué à 3.
Tu viens de montrer qu'il est techniquement possible de dériver de std::vector, c'est a dire que le compilateur ne génère pas de diagnostic. Le problème, c'est que le compilateur ne va pas t'avertir des dangers potentiels a l'utilisation.
En modifiant légèrement le main() :
On obtient a l'exécution :
Et pourtant, dans la fonction run(), c'est bien l'instance de MyVector qui est utillisée, n'est-ce pas ? Pourquoi le comportement du programme a-t'il changé ?
Tu auras aussi des résultats comiques si tu ajoute un destructeur spécifique a MyVector et que tu manipules tes instances par l'intermédiaire de pointeur sur sdt::vector...
Les containers de la STL ne sont pas conçus pour êtres dérivés en public, mais il n'y a pas de garde fou, comme d'habitude.
[^] # Re: Journal completement foireux
Posté par shbrol . En réponse au journal Bitcoin hors-la-loi, Tor victime collatérale. Évalué à 2.
Oui, sauf si c'est moi qui trouve ton portefeuille...
[^] # Re: The goat leash
Posté par shbrol . En réponse au journal Cherche exemple d'expression de calcul lourd. Évalué à 1.
Et depuis quand une clôture empêche une chèvre de brouter de l'autre coté ?