1080

oué ça fonctionne aussi cheeky

1081

D'ailleurs, j'ai pas trop compris la différence entre auto_ptr::get() et *auto_ptr
ça a pas l'air bien grave

1082

*auto_ptr renvoit l'objet pointé (de type T), get() renvoit l'adresse vers l'objet pointé (de type T*)
en gros *auto_ptr == *auto_ptr.get()
avatar

1083

Oué voilà, c'est conçu pour s'utiliser à peu près comme un pointeur normal.

1084

Ah ok merci, donc on peut faire un *ptr.truc() ou ptr.get()->truc(). Mais dans le cas d'un *ptr.truc(), on bosse sur une copie alors ?

1085

non, tu ne travailles pas sur une copie, tu travailles sur l'objet pointé directement, comme pour un pointeur normal.

et puis tu n'as pas besoin de passer part get() si tu veux utiliser les opérateurs * ou -> puisse qu'ils sont redéfinis dans la classe auto_ptr.
get() ne sert que quand tu veux explicitement récupérer l'adresse de l'objet géré par l'auto_ptr. sinon c'est transparent (il se pourrait mêem qu'un auto_ptr<T> puisse être casté implicitement en T*, genre quand tu le passes en paramètre à une fonction prenant un T* en entrée, à vérifier) non on peut pas, li faut utiliser get(). j'ai dû confondre avec autre chose
avatar

1086

Ah oui t'as raison, le pire c'est que j'ai lu la doc des opérateurs tout à l'heure couic

1087

GoldenCrystal (./1045) :
des solutions plus moisies les unes que les autres (cf ./1042 …)

Bah, pour quelqu'un qui a l'habitude de Qt (comme c'est mon cas), le partage implicit est tout à fait naturel.
Folco (./1064) :
Un objet A construit lors de sa propre construction deux objets B et C en tant que membres privés.
L'objet B se construit normallement.
La construction de C échoue et il lance une exception.

Si A n'intercepte pas l'exception, mais qu'elle est récupérée par une "catch all" général à la base du programme (genre dans main()), alors B sera perdu dans la nature ?Ca veut donc dire que c'est à A d'intercepter l'exception lancée par C pour nettoyer B avant de lancer sa propre exception ?

C'est à cause de ce genre de problèmes qu'un constructeur qui lance une exception, c'est totalement crade. Un constructeur n'a pas à échouer. Une solution est que si le constructeur échoue, on construit un objet non valide et on rajoute une méthode isValid. Cette technique est utilisée à plusieurs endroits dans Qt.
aze (./1072) :
note que dans ce cas, il vaut mieux utiliser un std::auto_ptr ou équivalent pour contenir B* et C*. un auto_ptr va détruire automatiquement l'objet pointé quand le pointeur dest détruit, contrairement à un pointeur normal. et là, plus besoin de try/catch dans A

Ou un QScopedPointer ou un QSharedPointer, qui résolvent tous les deux le problème du double free (QScopedPointer ne peut pas être copié, QSharedPointer compte les références comme il faut). std::auto_ptr est totalement foireux comme concept.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

1088

Kevin Kofler (./1087) :
Une solution est que si le constructeur échoue, on construit un objet non valide et on rajoute une méthode isValid.

Ca me tente bien. Des objections ?

1089

Ça ne me parait *pas très* standard, et donc l'utilisateur à toutes les chances d'oublier de vérifier que l'objet est valide... Au niveau confort d'utilisation de la classe, je trouve ça franchement moisi.

1090

./1088 > Ouais ! ^^
Le concept d'une exception est que ça fait « crasher » ton programme en cas d'erreur. (Sauf interception de l'erreur)
Un bête flag à tester, ça fera juste un plantage dans certains cas (ça peut aussi passer totalement inaperçu mais faire bugger ton programme) et ça peut être difficile à diagnostiquer.
La gestion d'exceptions c'est quand même un moyen propre de détecter des bugs, même si certains ont l'ait de trouver ça sale…
(J'ai un truc que je voulais dessiner là dessus pour mettre sur mon blog mais j'ai pas encore trouvé la motivation, ça viendra tongue)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

1091

guitar
Bref, poubelle direct©

1092

Ca me casse les bonbecs les exceptions, puis réfléchir à ça quand j'ai 3 ou 4 objets imbriqués c'est casse-kooyes, et ça fait vite 40 lignes de code (avec tout ce que t'as initialisé à dégager) juste en cas de merdance, c'est lourd.
A voir, standard ou pas on essayera tongue Surtout que je n'ai que moi comme seul utilisateur, et je me frapperai pas si j'oublie de vérifier une validité tongue

Et si c'est bien fait, je vois pas pourquoi ça crasherais, le but est justement d'éviter ça ^^

1093

Folco (./1088) :
Kevin Kofler (./1087) :
Une solution est que si le constructeur échoue, on construit un objet non valide et on rajoute une méthode isValid.

Ca me tente bien. Des objections ?

ouais, lance plutôt une exception.
justement, les exceptions t'éviteront d'écrire 40 lignes de code pour gérer si tu as 3 ou 4 objets imbriqués. tu n'auras pas à faire un test après chaque construction d'objet pour savoir si elle a réussi et donc si l'objet qui a appelé ce constructeur est valide
avatar

1094

Pen^2 (./1091) :
guitar
Bref, poubelle direct©

1095

./1092 > Non.
Quand tu as un bug, tu veux que le programme crash. Pour te dire « Il y a un problème. ».
Ce que tu ne veux pas c'est que dans ton dos, il se passe un truc subtil qui provoquera un crash pseudo aléatoire à un autre endroit du code, sans que tu trouves d'où il vienne.
Les exceptions sont les amies du développeur, pas ses ennemies !
T'as l'impression que ça augmente la quantité de code à écrire donc que ça n'en vaut pas la peine, mais la réalité c'est surtout que ça diminue le temps perdu à déboguer. wink
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

1096

Folco (./1088) :
Des objections ?
zWrM
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

1097

trilove
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

1098

trilove

1099

Bon ok, l'image m'a convaincu trilove

1100

\o/

1101

Bon alors petit retour sur le rectangle.
Brunni a la solution la plus élégante à mon gout: equilibre entre simplicité et respect des contrats. Elle permet aussi de factoriser assez facilement le code.

La solution de KK est une bonne branlette intellectuelle où on arrive à la fin en se demandant pourquoi on a une abstraction ModifySquare et AbstractRectangular. On a un héritage multiple (en C++), et aucune factorisation du code. C'est très alléchant sur le papier, mais peut utile je trouve dans un cas concret!
Sinon dommage Folco que tu n'ais pas présenté ta solution!

L'erreur que souvent un débutant commet est l'erreur de Squaly. Pour expliquer cette erreur il faut bien comprendre la notion de programmation par contrat.
Il y a une rupture du contrat: dans un carré, on a une condition invariante qui est coté = coté. De ce faite un rectangle ne peut évidemment pas dériver d'un carré.
Dans le cas de l'héritage inverse, si l'on choisit l'astuce du setter: setW(u): W=H=u, on a une rupture du contrat qui est lorsque que l'on défini W, h est constant.
Le carré et le rectangle étant divergeant sur la definition de la longueur et de la largeur, ces deux éléments ne peuvent pas être définis dans l'abstraction (hors constructeur).

Pour le deuxième sujet, l'exception est vraiment moche. Et je tenais juste à préciser qu'il ne faut pas mélanger construction et initialisation d'un objet.

1102

Flanker (./1044) :
Nil (./1039) :
Bah j'aurais pas fait exactement comme squalyl en fait, tiens... j'aurais surchargé les méthodes setWidth et setHeight pour qu'elles aient le même comportement (c'est à dire son setcote, quoi). Pas besoin d'un setcote.

Pareil

Ce n'est pas bon, parce que:
Rectangle c = new Carré();
c.setWidth(10);
c.setHeight(20);
System.out.println(c.getWidth() + "x" + c.getHeight());

Il est difficile de dire à quoi s'attendre... 20x20 sera le résultat, mais ça aurait pu être 10x10 ou même 10x20 en toute logique (mais à ce moment le carré est dans un état incohérent). Bref c'est pour ça qu'un carré n'est pas un rectangle, d'où ma solution ^^
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

1103

C'est surtout que si le carré derive du rectangle, il doit passer le teste unitaire du rectangle...

1104

(Je pense comprendre ce que tu veux dire par là même si j'en suis pas encore très loin en POO, mais mon explication comme quoi que le carré peut se retrouver dans un état incohérent s'il est modifié côté par côté comme un rectangle sera peut être plus parlante à Folco et autres ^^)
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

1105

JackosKing (./1101) :
Pour le deuxième sujet, l'exception est vraiment moche. Et je tenais juste à préciser qu'il ne faut pas mélanger construction et initialisation d'un objet.

Tu peux préciser les deux points stp, aussi bien sur l'initialisation que l'exception ?

edit -> en fait, je pense faire la différence entre création et initialisation (création des objets composants l'objet en question VS initialisation des pointeurs via des new, des différentes données à des valeurs précises et de l'appel aux initialisateurs des autres objets). C'est pas ça ?
Si oui, pourquoi différencier les deux ? C'est pas cool de pouvoir tout mettre dans le constructeur et lancer une exception au cas où ya le moindre truc qui déconne ?

note : je ne me place __jamais__ dans le cas de la réutilisation d'une classe, ni dans le cas d'un quelconque client qui utiliserait ma classe smile

1106

Si ça peut te rassurer je ne comprends pas vraiment non plus. Par exemple avec le modèle des fichiers selon Java ça n'a pas de sens de créer l'objet InputStream si le fichier ne peut être ouvert puisqu'il représente justement un fichier ouvert, tu vois? Donc c'est tout naturel de lancer une exception et stopper la création de l'objet si le fichier associé ne peut être ouvert.

Dans le cas d'un rectangle c'est un peu différent, puisqu'on peut modifier cette propriété par après (en fait dans le cas du fichier, le 'stream' est associé à un et un seul fichier ouvert, alors qu'un rectangle donné n'a pas une taille figée). On peut donc dire que ce n'est pas un drame s'il est impossible de créer un rectangle de taille négative, puisqu'on pourrait toujours le modifier plus tard pour qu'il ait une taille valable.

Maintenant tout ça me semble être un peu trop théorique, et dans la pratique si tu fais une API pour toi même, il est clair que si tu essaies de créer un rectangle de taille négative alors tu es en train de *faire de la merde* (c'est à dire que soit ton code, soit la saisie de l'utilisateur sont à la rue), donc ça peut être pas mal d'en être averti et sortir de l'exécution -> exception, refus de créer l'objet et donc continuer.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

1107

JackosKing (./1103) :
C'est surtout que si le carré derive du rectangle, il doit passer le teste unitaire du rectangle...

Pour cela, il faut déjà qu'il y en ait un. gni
Folco (./1105) :
JackosKing (./1101) :
Pour le deuxième sujet, l'exception est vraiment moche. Et je tenais juste à préciser qu'il ne faut pas mélanger construction et initialisation d'un objet.

Tu peux préciser les deux points stp, aussi bien sur l'initialisation que l'exception ?

edit -> en fait, je pense faire la différence entre création et initialisation (création des objets composants l'objet en question VS initialisation des pointeurs via des new, des différentes données à des valeurs précises et de l'appel aux initialisateurs des autres objets). C'est pas ça ?Si oui, pourquoi différencier les deux ? C'est pas cool de pouvoir tout mettre dans le constructeur et lancer une exception au cas où ya le moindre truc qui déconne ?

Si j'ai bien compris, son idée, c'est qu'au lieu d'avoir:
Classe objet; // peut échouer, mais comment le détecter?
tu as:
Classe objet; // objet n'est pas encore initialisé/utilisable
if (!objet.init()) FAIL; // initialise l'objet, retourne true (succès) ou false (échec)

C'est une variante de la méthode de la méthode isValid() (./1087), tu peux toujours avoir une méthode isValid() d'ailleurs, mais son comportement sera différent. La méthode du ./1087, c'est:
Classe objet; // initialise l'objet, peut échouer
if (!objet.isValid()) FAIL;

Celle du ./1101 avec une méthode isValid(), c'est:
Classe objet; // objet n'est pas encore initialisé/utilisable
// ici, objet.isValid() == false
bool valid1 = objet.init();
bool valid2 = objet.isValid();
// ici, valid1 == valid2
if (!valid1) FAIL;
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

1108

Ah ok merci. Alors vous pouvez vous empoigner sur cette question svp ? Plutôt "Exception" ou "objet.init()" ? cheeky

1109

Perso j'aime pas. Si un objet ne peut même pas être initialisé tel que l'utilisateur le désire ou si un composant qui lui est nécessaire subit le même sort, alors l'objet n'a pas de raison d'être "vivant" puisqu'il est dans un état incohérent ou "bidouillé" (p.ex. rectangle de 0x0).
Pour une raison de clarté, j'aime bien que les objets aient une seule fonction durant leur vie. On crée l'objet pour une tâche, on la fait et on détruit l'objet. Si on en a besoin à nouveau on le recrée. Le modèle du C++ permet par ailleurs de faire ça sans pénalité de performance au contraire de certains langages obligeant l'allocation sur le heap (Objective C) ou dans une moindre mesure pour les langages avec ramasse-miettes comme Java.
Bon après tout dépend du cas. Par exemple j'ai fait récemment une API graphique pour un petit jeu qu'on fait dans un cours, et on peut prendre 2 cas qui illustrent la scission.
Premièrement un rectangle (héritant de GLComponent, mettant à disposition les méthodes Move, Draw, etc.):
// La construction ne peut pas échouer; par défaut tout composant est unitaire,
// placé à (0, 0), blanc, de centre (0, 0) etc. donc l'état initial est connu et
// cohérent pour l'utilisateur
GLRectangle rect = new GLRectangle();
rect.Move(10, 10).Size(20, 20).Rotate(30).Draw();

Mais pour une image par exemple on a une relation de composition* avec GLTexture, représentant l'image chargée, relation qui est très lourde d'implications:
// La construction *peut* échouer (exception) car une image sans texture
// n'en est pas une...
GLImage img = new GLImage("test.png");
img.SetColor(Color.Green).Draw();

(* en réalité c'est une agrégation dans ma modélisation, mais dans ce petit exemple pas besoin de s'embêter avec ça)
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

1110

Brunni (./1102) :

Ce n'est pas bon, parce que:
Rectangle c = new Carré(); c.setWidth(10); c.setHeight(20); System.out.println(c.getWidth() + "x" + c.getHeight()); Il est difficile de dire à quoi s'attendre... 20x20 sera le résultat, mais ça aurait pu être 10x10 ou même 10x20 en toute logique (mais à ce moment le carré est dans un état incohérent). Bref c'est pour ça qu'un carré n'est pas un rectangle, d'où ma solution ^^


Bah non, avec ma solution, setWidth et setHeight font exactement la même chose ; le carré aura donc une taille de 20x20 (logique, d'ailleurs... tu étires le carré par un de ses côtés, puis tu changes la taille d'un autre côté : le carré aura un côté de la taille finale, point barre)
avatar