moi je n'ai toujours pas compris si il fallait gerer les references dans 1. un seul objet graph (compliqué ou non) ou dans 2. tout le programme.
si c'est 2. alors la solution de medinoc est bonne.
moi je n'ai toujours pas compris si il fallait gerer les references dans 1. un seul objet graph (compliqué ou non) ou dans 2. tout le programme.
si c'est 2. alors la solution de medinoc est bonne.
Screetch, je ne pense pas t'avoir demander de me générer le vcproj
J'ai simplement demander a tout les lecteurs si quelqu'un l'avait déja utilisé avec visual, et dans ce cas savoir si je peux downloader le .sln quelque part, ou qu'on puisse me le fournir moyennant de ma part un grand merci, un merci d'un développeur de la communauté qui galere malheuresement comme beaucoup...
Merci du tuyau, je vais générer le projet avec NMAKE et voir ce que ca donne, super![]()
un GC me parait overkill pour ce probleme, mais bon ...
en plus avec des problemes de portabilité à prévoir
Oui mais je pense que je n'ai pas trop le choix, j'ai des centaines de references croisées et auto-references, ca génere des memory leaks.
D'ailleurs y a 2 projets opensource qui font la meme chose que ma javascript virtual machine , Spidermonkey et Rhino, les 2 utilisent un GC certainement pour les meme raisons que moi.
SpiderMonkey est lent a cause du GC apparemenent, et Rhino a des fuites memoires...
Si tu a une autre idée que ce GC je suis prenant.
Merci
tu parles de graph ou de programme?
1. un objet graphe avec des noeuds?
2. un programme avec plein d'objet se référençant?
le premier est "facile", le deuxième l'est nettement moins et ressemblerait a un programme java.
pour le deuxième, c'est pas facile... il faut passer par encapsuler tes pointeurs dans des objets qui gardent les références... mais c'est dur à dire sans même voir un bout de code :-/
J'ai pas tout compris alors je me contente d'un "+1" évocateur
Tu ne peux pas utiliser de librairie, mais tu peux écrire du code quitte à faire du copier/coller/adapter des sources d'une librairie connue ou d'ailleurs.
Voici un petit bout de code qui rejoint la proposition de Médinoc:C'est un smart pointer qui maintient ses références dans une liste doublement chainée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 template<class T> class c2smart_ptr { T *f_ptr; c2smart_ptr<T> *f_ap,*f_apr; void Attach(const c2smart_ptr<T> *p) { f_apr=(f_ap=p->f_ap)->f_apr; f_ap->f_apr=f_apr->f_ap=this; } void Detach() { f_ap->f_apr=f_apr; f_apr->f_ap=f_ap; } public: c2smart_ptr() :f_ptr(0) {f_ap=f_apr=this;} explicit c2smart_ptr(T *ptr) :f_ptr(ptr) {f_ap=f_apr=this;} template<class Y> c2smart_ptr(const c2smart_ptr<Y> & r) :f_ptr(r.get()) { Attach(reinterpret_cast<const c2smart_ptr<T> *>(&r)); } c2smart_ptr(const c2smart_ptr<T> & r) :f_ptr(r.f_ptr) { Attach(&r); } c2smart_ptr<T> & operator=(const c2smart_ptr<T> & r) { if (&r!=this) { c2smart_ptr<T> t(*this); //keep this line ! Detach(); f_ptr=r.f_ptr; Attach(&r); } return *this; } ~c2smart_ptr() { if (f_ap==this) delete f_ptr; else Detach(); } T & operator*() const { return *f_ptr; } T *operator->() const { return f_ptr; } T *get() const { return f_ptr; } };
Simple, concis et vérifié (par moi, et bientôt par toute la communauté C++ de developpez.net
)
merci a tous, copier du code serait inutile dans ce cas.
Pour expliquer ce que j'entend pas object graph est-il possible ici de poster un lien vers une page web? ou cela est interdit?
voila ce que j entend par object graph, ce sont des objets contenant des references sur d autres objets, sur eux memes, etc...
Le probleme est qu avec des refcount, il n est pas possible de gerer les references cycliques ou autoreferences.
Tout la est mon probleme, les objet 3, 5 et 6 ne sont pas deletable, il faut manuellement casser les references croisees et auto pour eviter les memory leaks. Ou bien utiliser des weaks pointers, mais c est pas evident vu la complexite avancee de mon object graph, celui ci est juste un exemple tres facile a gerer.
Voila en esperant un peu d aide
Merci
Ce serait intéressant de voir un bout de code qui représente ce shéma, et montrer que des smart pointer ne suffiraient pas.
Comme ça, à froid:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 struct Object { std::list< shared_ptr<Object> > f_obj_list; }; shared_ptr<Object> o1,o2,o3,o4,o5,o6; o1=make<Object>(); o2=make<Object>(); o3=make<Object>(); o4=make<Object>(); o5=make<Object>(); o6=make<Object>(); o1.f_obj_list.insert(o3); o1.f_obj_list.insert(o4); o2.f_obj_list.insert(o4); o3.f_obj_list.insert(o5); o5.f_obj_list.insert(o3); o6.f_obj_list.insert(o5); o6.f_obj_list.insert(o6);
j ai jamais travailler avec la SL sharedpointer, en fait je dirais plutot :
Dans le diagramme chaque case est l instance elle meme(a), pas la reference(b).
Donc quand tu quitte ton main admettons que o1 soit deleter le premier, o4 reste en vie car retenu par o2, puis si tu delete o2, o4 est delete aussi.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 class MyClass { shared_ptr<MyClass> m_ref1; shared_ptr<MyClass> m_ref2; }; //main, la on cree toutes les objets(cases dans le schema) shared_ptr<MyClass> o1 = new MyClass(); // la syntaxe est surement fausse, c est juste pour montrer le principe shared_ptr<MyClass> o2 = new MyClass(); shared_ptr<MyClass> o3 = new MyClass(); shared_ptr<MyClass> o4 = new MyClass(); shared_ptr<MyClass> o5 = new MyClass(); shared_ptr<MyClass> o6 = new MyClass(); //la on "cree" les fleches dans le schema(references) o1.m_ref1 = o3; //fleche o1->o3 o1.m_ref2 = o4; //fleche o1->o4 o2.m_ref1 = o4; // ref croisee o3.m_ref1 = o5; o5.m_ref1 = o3; o6.m_ref1 = o5; o6.m_ref2 = o6;
Par contre tout le reste n est jamais deleter car o3 et o5 sont retenus mutuellement, leur refcount est pour o3=1(retenu par o5), o3=2(retenu par o3 et o6) et o6=1(retenu par lui meme).
Il est possible de manuellement casser la reference croisee o3-o5 et l autoreference o6-o6, avant de quitter le main. Dans ce cas chaque destruction entraine une autre, tout est deleter.
Mon souci majeur est que ce schema est ridiculement simple, ce que j ai en realite est 50 fois plus complique, et quand je dis 50 fois c est vraiment pas une blague.
Sans compter que ce schema dans mon cas reel est dynamique, selon le contexte, j ai un schema different.
La question initiale de ce post, est de savoir comment regler ce probleme sans garbage collector...
Merci
En effet, ce petit bout de code prouve le memory leak:Moi qui croyait que les smart pointer était la solution à tous les maux provoqués par les pointeurs
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 #include "boost/make_shared.hpp" #include <list> struct Object { std::list< boost::shared_ptr<Object> > f_obj_list; int f_n; Object(int n):f_n(n) {std::wcout << "Object " << f_n << std::endl;} ~Object() {std::wcout << "~Object " << f_n << std::endl;} }; int main() { boost::shared_ptr<Object> o1,o2,o3,o4,o5,o6; o1=boost::make_shared<Object>(1); o2=boost::make_shared<Object>(2); o3=boost::make_shared<Object>(3); o4=boost::make_shared<Object>(4); o5=boost::make_shared<Object>(5); o6=boost::make_shared<Object>(6); o1->f_obj_list.push_back(o3); o1->f_obj_list.push_back(o4); o2->f_obj_list.push_back(o4); o3->f_obj_list.push_back(o5); o5->f_obj_list.push_back(o3); o6->f_obj_list.push_back(o5); o6->f_obj_list.push_back(o6); }(j'ai jamais eu non plus à gérer des références cycliques)
Ben à mon avis, les réponses à ta question intiale sont:
1) tolérer les memory leak
2) revoir le concept de l'application
3) retenir toutes les instances lors de leur création et vérifier périodiquement, une par une, si elles sont toujours viables (suivant quelle critère ?)
Quoiqu'il en soit, je serais curieux de savoir comment tu auras résolu ton problème.
tu as lu mon post ?
http://www.developpez.net/forums/d82...e/#post4769669
du moment que tu as un graph que tu peux parcourir alors c'est possible.
la je pense qu'il faudra stoker tous les pointeurs de tes objets puis parcourir ton graph pour identifier les manquant, ceux que tu devras effacer avec delete.
<EDIT>il y a moyen de mieux faire avec de l'incremental donc d'eviter de stoker en double toutes les references</EDIT>
je ne sais pas comment est fait ton graph, tu diras peut-etre voire surement que c'est trop dur, alors montre nous un bout de code pour expliquer comment est concrètement fait ton graph
oui j'ai lu ton post, grosso modo le principe est de garder une trace des references, mais a quel moment dois-je enclencher la deletion des objets restants??
Mon application crée en permanence des references cycliques et en perd la trace. A quel moment donc les deleter?
Cela revient finalement a un garbage collector...
option 1: tu pourrais surcharger l'operateur "new" pour garder la trace de tous les objets, ainsi quand tu veux, tu peux parcourir ton graph et identifier les manquants
option 2: tu surcharges l'operateur "delete" (attention: ne pas deleter ses noeuds pour ne pas faire de recursion) pour garder les références peut-etre effacées, ensuite quand tu parcours ton graph, tu enleves de la liste ceux qui sont encore presents dans le graph, et tu inspectes les noeuds descendant de ceux que tu veux effacer... il est donc incremental puisqu'il faudra attendre le parcours suivant pour les effacer (ou pas)
Quand declencher ce parcours du graph et lu suppression effective avec "delete"?
A. soit un thread a part qui declenche l'operation tous les x millisecond
B. tu testes a un endroit de ton code si la liste fait plus que n elements, tu declencles l'operation
l'option A est plus delicate car il faudra protéger ton graph (les "ajouts" de noeuds + surement autre chose que j'oublie)
oui c'est une sorte de GC, mais spécialisé pour ton cas et surement plus multi-plateform qu'un vrai GC type Boehm.
J'ai cru comprendre que l'option multi plateform était ton intérêt premier non?
d'autre part, par exemple, le GC de objective C sur i-phone n'est pas disponible sur i-phone... donc je dirais que les GC généraux sont peut-etre un problème avec des ressources limitées.
<EDIT> les GC sont vraiment un domaine a part entière, j'ai cru comprendre que javascript core (webkit) le faisait par analyse de l'AST.
http://trac.webkit.org/wiki/JS%20Cor...ge%20Collector
question: Pourquoi avez-vous développé votre propre javascript compilateur?
javascript core de webkit ne répondait pas du tout au besoin?
</EDIT>
en fait il s'agit un javascript compilé, un .js compilé en .cjs. Car pour un telephone mobile, un interpreteur est trop lent. Ma JSVM execute le bytecode du cjs.
Pour cela l'application est designée avec des references cycliques.
C'est similaire a SpiderMonkey ou Rhino.
Bon on a une version Java de cet JSVM, je l'ai porté en natif.
penses-tu que faire ce que je propose est possible ou non?
ton option B, disons, a quel endroit dois-je enclencher l'opération??Quand ma memoire physique disponible atteint un seuil?B: tu testes a un endroit de ton code si la liste fait plus que n elements, tu declencles l'operation
Tu pourrais détailler stp, et pour repondre a ta question precedente, oui le multi-platforme est mon probleme principal.
J'avais pensé a la base a memoriser les references cycliques quelque part, et les deleter a un certain moment avec un thread.
Cependant, le design de notre application a changé entre temps et on a un object graph d'une complexité bien plus avancée.
j'aurais par exemple fait un thread qui envoie un message tous les x (milli)secondes donc comme ca tu n'aurais pas eu besoin de proteger ton code contre les acces concurrentiels...
... remarque, un timer marche aussi comme cela.
si tu ne peux faire ni l'un ni l'autre,
alors je l'aurais placé dans la boucle a message...
si tu n'en as pas, tu peux toujours le mettre dans l'operateur delete.
... et finalement tout compte fait, dans le "delete", ne serait-ce pas la meilleure solution?
<EDIT> avec une durée minimal entre 2 lancements, et/ou un nombre minimal d'objets à tester </EDIT>
Plus de memory leak avec ceci:Dites les pros du smart pointer, vous auriez pu dire qu'il suffisait d'utiliser weak_ptr
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "boost/make_shared.hpp" #include "boost/smart_ptr/weak_ptr.hpp" #include <list> struct Object { std::list< boost::weak_ptr<Object> > f_obj_list; int f_n; Object(int n):f_n(n) {std::wcout << "Object " << f_n << std::endl;} ~Object() {std::wcout << "~Object " << f_n << std::endl;} }; int main() { boost::shared_ptr<Object> o1,o2,o3,o4,o5,o6; o1=boost::make_shared<Object>(1); o2=boost::make_shared<Object>(2); o3=boost::make_shared<Object>(3); o4=boost::make_shared<Object>(4); o5=boost::make_shared<Object>(5); o6=boost::make_shared<Object>(6); o1->f_obj_list.push_back(o3); o1->f_obj_list.push_back(o4); o2->f_obj_list.push_back(o4); o3->f_obj_list.push_back(o5); o5->f_obj_list.push_back(o3); o6->f_obj_list.push_back(o5); o6->f_obj_list.push_back(o6); }![]()
non un weak_ptr ne locke pas contre la destruction...
un weak_ptr est un pointeur amélioré dans le sens ou tu peux savoir qu'un objet est deleté. C'est aussi pour ca qu'il se construit a partir d'un shared_ptr
<EDIT> ton exemple ne marche que parce que tu as fait des smart_ptr pour tous les objets au début. ce n'est donc pas un graph ...
</EDIT>
un extrait tiré de la doc de boost:
Q. Can an object create a weak_ptr to itself in its constructor?
A. No. A weak_ptr can only be created from a shared_ptr, and at object construction time no shared_ptr to the object exists yet. Even if you could create a temporary shared_ptr to this, it would go out of scope at the end of the constructor, and all weak_ptr instances would instantly expire.
Partager