900

<mylife>
c'est rigolo comme on peut enchainer les appels de méthodes quand les valeurs de retour sont des objets cheeky
m_ModuleList->back()->manageEvents(&Events, &Messagebox)->dispPlane(&m_MainScreen);
Comment ça c'est pas bien pour la lisibilité ? grin
</>

901

m_ModuleList->back()
   ->manageEvents(&Events, &Messagebox)
   ->dispPlane(&m_MainScreen);

C'est joli aussi ^^
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

902

Ah pas mal, faut que j'essaye, mais déjà ça parait bien plus lisible, merci bien happy

903

c'est pour les tapettes cette écriture

904

Pour éviter d’avoir à écrire « & » avant chaque paramètre (c’est juste moins agréable à lire avec le &), tu peux utiliser le passage d’argument par référence :
void maFonction(Objet & objet);

Objet monObjet;
maFonction(monObjet); // l’objet n’est pas copié, c’est son adresse qui est passée, comme si tu avais écrit &monObjet

Tu peux aussi spécifier encore le plus le contrat passé par la fonction : a-t-elle le droit de modifier l’objet en paramètre ?
void maFonction(const Objet & objet); // maFonction ne modifiera pas objet
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

905

Je signale quand-même que le passage par référence non-const est contraire aux principes de style Qt parce que ça cache le fait que le paramètre peut être modifié, l'équipe Qt conseille d'utiliser les pointeurs parce qu'on voit plus clairement ce qui se passe.

De plus, un pointeur, ça permet de passer NULL si on n'a rien à battre d'une sortie (à condition que la fonction vérifie ce cas, évidemment), une référence oblige à passer un objet temporaire bidon (parce qu'on n'a pas le droit d'avoir une référence sur NULL, le comportement est indéfini si on en a une).

Mais comme toute question de style, ça se discute.
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é

906

Effectivement c’est traître en C++ : quand on appelle une fonction on ne voit pas directement si on passe les paramètres par référence ou valeur.

Après tu peux prendre pour convention de toujours passer tes objets par référence const, comme ça tu sais toujours ce que tu fais.

Sinon, le fait de pouvoir renvoyer NULL est très dangereux et peut conduire à des Protected Memory Violation (ou NullPointerException en Java) si l’appelant ne prend pas la peine de vérifier résultat.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

907

1. Si j'utilise des références, ce sera toujours en utilisant const pour les raisons que vous avez évoquées. Personnellement, je trouve que comme chausse-trape c'est idéal les références (des faux objets qui sont en fait des vrais pointeurs que l'on utilise comme des vrais objets sick), du moins avec mon niveau de C++, de design et de spec. Donc je m'en passe. Avec un pointeur, je sais ce qui se passe.
2. Je vérifie toutes mes valeurs de retour, donc pas de souci.

908

Quelqu'un peut-il confirmer ma révélation du jour ? (ou plutôt de la nuit, mébon...)
"Si chaque objet fais gaffe à détruire, dans sont destructeur, les autres objets et espaces mémoires qu'il a alloué, alors on ne leakera pas de mémoire".

Puissant, non ? Je crois que je me posais trop de questions en fait triso Et oui, ya rien à comprendre mais c'est comme ça

909

Y'a aussi des modèles dans lesquels un objet prend possession d'un autre objet, et doit donc se charger de le libérer, même si c'est pas lui qui l'a alloué (donc celui qui lui passe l'objet ne doit en échange surtout pas le libérer). Ainsi que des modèles où une fonction te retourne un pointeur vers objet que tu dois donc libérer ensuite, etc.
Ce qui compte c'est que les deux côtés soient d'accord sur ce qu'ils font. (Mais il faut faire les bons choix au bons endroits, tous les modèles sont acceptables si bien utilisés)
Après tout, le double-free est tout aussi méchant que la fuite de mémoire smile
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

910

Folco (./908) :
"Si chaque objet fais gaffe à détruire, dans sont destructeur, les autres objets et espaces mémoires qu'il a alloué, alors on ne leakera pas de mémoire".

Bah oui, c'est évident. On appelle ça le principe RAII.
GoldenCrystal (./909) :
Après tout, le double-free est tout aussi méchant que la fuite de mémoire smile

C'est même pire, ça plante l'application et ça peut même être exploitable pour exécuter du code arbitraire (même si les systèmes d'exploitation récents ont des protections qui rendent un tel exploit plus difficile voire impossible).
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é

911

Kevin Kofler (./910) :
(même si les systèmes d'exploitation récents ont [...]

C'est cool que tu t'intéresses toujours à Windows smile
Sinon perso je fais des trucs du genre:
typedef const class Vector &CVector;
class Vector {
    int x, y;
public:
    Vector(int x, int y) : x(x), y(y) {}
    Vector operator + (CVector v2) {
        return Vector(x + v2.x, y + v2.y);
    }
};

Et je n'utilise jamais le & dans mon code en général (hormis cas spéciaux comme void swap(int&, int &) par exemple). Le C++ est fait de telle manière que ce soit en général plus cohérent d'utiliser des pointeurs (et plus pratique aussi). Par exemple le this est un pointeur et pas une référence (ça paraît complètement illogique). On ne peut pas non plus "retenir" une référence.
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

912

Brunni (./911) :
C'est cool que tu t'intéresses toujours à Windows smile

Les versions récentes de la glibc ont aussi une protection contre les doubles frees.

Et au fait, la Data Execution Prevention (DEP) n'est qu'une copie de ExecShield que Red Hat propose depuis longtemps. tongue
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é

913

Kevin Kofler (./910) :
Bah oui, c'est évident. On appelle ça le principe RAII.

C'est évident quand on sait cheeky Sauf que le fait de sortir de mes objets par une exception me posait pas mal de questions.

Mais mes objets sont tous "chainés" :
main() crée un Task qui crée un Plane et des Module qui créent des ItemsList et des Icons etc...
Suffit que le destructeur de Task détruisent son Plane et ses Module qui détruiront leurs ItemsList et leurs Icons qui [.....]

Je n'étais pas sûr du comportement suite à une exception déclenchée "assez bas" dans la hiérarchie des objets et interceptée au niveau de main(). Mais puisque main() crée et donc détruit Task, il s'en suit que tous les autres objets et allocations seront détruit en chaine à la sortie du programme. smile

914

Je préfère le terme "RRIF" (Resource Release Is Finalization) qui est plus parlant sur l'aspect "destruction" de l'objet.

Ensuite, au sujet des questions de double-free, c'est la raison pour laquelle si l'on définit un destructeur, l'on doit aussi définir (ou interdire, en les déclarant private sans les définir) le constructeur de copie et l'opérateur d'affectation. Prévoir une fonction de Swap, c'est souvent utile.
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

915

Je définis et mets en private tous les opérateurs de copie et d'affecation dont je ne veux pas me servir, c'est à dire beaucoup dans le cadre de mon jeu : copier un conteneur se conçoit, copier la bataille en cours beaucoup moins.

916

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é

917

Meric pour l'équivalence. Ca déclare aussi une variable static pour faire des singletons ? Ou c'est juste la copie/affectation qui est interdite ? Si c'est juste ça, comment font-ils pour que Truc x = Truc() ne marche pas ?

918

apparemment le constructeur de copie est rendu privé.

919

/*
   Some classes do not permit copies to be made of an object. These
   classes contains a private copy constructor and assignment
   operator to disable copying (the compiler gives an error message).
*/
#define Q_DISABLE_COPY(Class) \
    Class(const Class &); \
    Class &operator=(const Class &);
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é

920

Sinon, il y a aussi la solution de faire hériter sa classe de boost::non_copyable, qui est plus ou moins... Une classe avec la même chose.
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

921

Ah ok, ben c'est ce que je fais alors, rien de plus.

922

bon, question très théorique.

Si j'ai une classe purement virtuelle (toutes ses méthodes sont virtuelles et non implémentées), quel est son intérêt ? De toute façon, je dois tout réimplémenter tout ce qui en dérive. C'est juste une manière de pouvoir faire du polymorphisme ?

923

A ce moment là c'est une interface (c'est comme ça qu'on les fait en C++). Si tu cherches ce mot tu verras plein d'infos sur l'utilité hehe (tu dois sûrement déjà avoir une idée puisque tu te poses la question). Et oui ça sert au polyomrphisme.
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

924

Ça sert à donner un nom à un ensemble d’opérations. De cette façon, tu sais que n’importe quelle classe qui implémentera cette interface fournira ces opérations. Et en général tu t’arrange pour regrouper des opérations qui ont un sens ensemble.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

925

Ok, merci bien. Je me suis demandé ça, parce que ma classe mère module voit en fait ses méthodes redéfinies de manière totalement différentes dans chacune de ses dérivées, et elle n'a de plus aucun attribut privé. Je me retrouve donc avec un tas de méthodes virtuelles et des attributs protected, mais je ne savais pas que ça s'appelait une interface. j'ai vu passer ça dans mon bouquin de C++ pourtant (il donne quelques tips "en java" pour préparer celui qui voudrait s'y mettre).

Autre question, qui doit être récurrente dans les classes dérivées, ou du moins au niveau des attributs protected. Qui doit détruire ces objets ? La classe dérivée qui en a connaissance lors de la dérivation, ou la clase mère qui possède ces attributs ? J'ai l'impression que les deux sont équivalents, ou du moins je ne discerne pas les subtiles différences. y aurait-il alors une convention usuelle ?

926

À toi de définir les responsabilités. C’est juste une convention à suivre. Mais il y a des conventions plus intuitives que d’autres (tant que t’as pas de contraintes de dépendances qui viennent foutre le bordel). En général je fais construire et détruire les objets par la même classe.
Donc là je dirais que la classe mère s’occupe de construire et détruire ses attributs de classe, et les filles s’occupent de construire et détruire ceux qui leur sont propres.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

927

Non, les deux ne sont pas équivalents. La classe qui détruit les objets est celle qui en a pris possession (donc en général celle qui les crée). Ce n'est pas aux classes enfants de nettoyer les cochonneries de la classe parent, sinon, qui nettoierait quand tu instancies directement la classe parent ?
Après, tu peux avoir des scénarios plus complexe, ou l'enfant et le parent suivent certains protocoles qui vont changer la donne (regarde le concept d'héritage multiple si tu veux t'amuser trivil), mais pour l'instant considère que alloué par la classe A = libéré par la classe A et rien d'autre.
D'autre part, pense bien à déclarer des destructeurs virtuels, ça t'évitera des erreurs chiantes tongue
(cross 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

928

Ca signifie donc que la classe mère comporte un constructeur, alors qu'on pourrait s'en passer si la classe dérivée construisait les objets protected. Ok.

Sinon, g++ refuse que mon destructeur de classe mère ne soit pas virtuel, pourquoi ? Quelle est la conséquence que ce destructeur soit virtuel ? Il va en fait être redéfini par la classe dérivée, mais les deux destructeurs seront appelés simultanément lors de la destruction de l'"objet dérivé" ? (CROSS !!! Je tombe sur ça GC, mais pourquoi ???)

Pour continuer le cross, oui, j'ai relu cet après-midi le chapitre sur l'héritage multiple, ça suppose visiblement de bien poser ses mécanismes d'héritages et de virtualisation pour ne pas se faire baiser...

Et enfin, je suis dans le cas d'une classe mère jamais instanciée en stand-alone (aucun intérêt, l'objet n'est pas fait pour ça et ne représenterait rien). C'est d'ailleurs pour ça que toutes ses méthodes sont virtuelles, sans implémentation.

929

C'est marrant en java, j'ai jamais eu ces soucis.

loin de troller, je veux souligner la simplicité et la propreté.

930

Folco (./928) :
Ca signifie donc que la classe mère comporte un constructeur, alors qu'on pourrait s'en passer si la classe dérivée construisait les objets protected. Ok.
Ça c'est pas vraiment (pas du tout) une manière propre de faire.
Sinon, g++ refuse que mon destructeur de classe mère ne soit pas virtuel, pourquoi ? Quelle est la conséquence que ce destructeur soit virtuel ?
Tiens je savais pas que le compilo t'interdisait carrément les destructeurs non virtuels ^^
Mais en gros c'est simple. Normalement, le C++ est compilable sans RTTI (l'équivalent très modeste de la réflexion en C# ou Java).(); // B dérive de ADonc si tu déclares A* truc = new BAlors, le compilateur sait juste que "*truc" est de type A. Si ton destructeur n'est pas virtuel, il va apeller le destructeur de A, puisque il sait seulement que *truc est de type A.
En revanche, avec un destructeur virtuel, il va apeller le destructeur attitré à "truc", à savoir soit le destructeur de A, soit celui de B si B a redéfini le destructeur de A… Tes ressources seront ainsi bien libérées comme il faut.
Il va en fait être redéfini par la classe dérivée, mais les deux destructeurs seront appelés simultanément lors de la destruction de l'"objet dérivé" ? (CROSS !!! Je tombe sur ça GC, mais pourquoi ???)
Ils ne sont pas appelés simultanément. Les éléments de la classe enfant dépendent (potentiellement) des éléments de la classe parent.
C'est comme quand tu t'habilles et te déshabilles. Tu mets d'abord le slip, puis le pantalon, et puis tu retires le pantalon avant de retirer le slip (car le pantalon est par dessus le slip). Tu ne peux pas retirer le slip avant le patanlon (enfin, tu peux en te tordant bizarrement, ok…), à moins que tu n'aies également mis le slip après avoir mis le pantalon tongue
Pour continuer le cross, oui, j'ai relu cet après-midi le chapitre sur l'héritage multiple, ça suppose visiblement de bien poser ses mécanismes d'héritages et de virtualisation pour ne pas se faire baiser...
Bah, le C++ est un peu trop permissif sur ce point malheureusement, mais si tu te limites à de l'héritage multiple propre comme en C#, Java & compagnie, y'a pas besoin d'énormément de contorsions neurales ^^
Et enfin, je suis dans le cas d'une classe mère jamais instanciée en stand-alone (aucun intérêt, l'objet n'est pas fait pour ça et ne représenterait rien). C'est d'ailleurs pour ça que toutes ses méthodes sont virtuelles, sans implémentation.
Ouais, mais dans beaucoup de cas tu auras également besoin d'une classe abstraite, proposant une partie de l'implémentation, et demandant aux enfants d'implémenter le reste. Une classe purement abstraite (une interface), par contre, ne doit pas déclarer quoi que ce soit d'autre que des méthodes virtuelles "pures" (au sens C++).
D'ailleurs j'espère que tu as bien pensé à déclarer tes méthodes comme telles ^^
(PS: virtual void machinChose() = 0wink
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