Subj : Re: Custom C++ objects with references and garbage collecting in To : netscape.public.mozilla.jseng From : Shanti Rao Date : Fri Mar 18 2005 09:16 pm Hi Mads, I solved this problem by using smart pointers. The code is at http://www.jsdb.org/jsdb.h and it works something like this: You use these macros to to replace JS_GetPrivate() and JS_SetPrivate() #define GETPRIVATE(x,obj) (((JSPointer*)JS_GetPrivate(cx,obj))->P) #define GETPOINTER (((JSPointerBase*)JS_GetPrivate(cx,obj))) #define SETPRIVATE(obj,x,t,ad,parent) \ JS_SetPrivate(cx,obj,new JSPointer(parent,t,ad)) #define DELPRIVATE(x) \ JSPointer * t = \ (JSPointer*)JS_GetPrivate(cx,obj);\ if (t) delete t; t=0; JS_SetPrivate(cx,obj,NULL) #define CLOSEPRIVATE(x) \ JSPointer * t = \ (JSPointer*)JS_GetPrivate(cx,obj);\ if (t) t->Close() A finalize function looks like this void Table_JSFinalize(JSContext *cx, JSObject *obj) { DELPRIVATE(DataTable); } When you want to create a JSObject representation of a child class in B::GetA(), you call a function like this: JSObject* New_Object(JSContext *cx, TParameterList* t,bool autodelete,JSPointerBase* Parent) { JSObject* obj; obj = JS_NewObject(cx, ...,..., NULL)); JS_DefineFunctions(cx,obj,functions); JS_DefineProperties(cx,obj,properties); SETPRIVATE(obj,TParameterList,t,autodelete,Parent); return obj; } If 'autodelete' is false, this pointer system will ensure that if B is garbage collected, then the actual C++ object representing B will not be deleted. Instead, its child A objects keep track of it, and the B object gets cleaned up AFTER the last A object is GC'd. Presto! Shanti > Hi all > > I have been searching for an answer to this question, and I sure hope > someone can help me out. Say I have the following classes > > > class A { > ... > } > > class B { > ... > public: > class A & getA(int i); > } > > and that both are exposed to the JS engine, using the private data to > store a pointer to the object. > > Now, using C++ code, these classes have the problem that the following > code is wrong: > > B b = new B(); > A & a = b.getA(0); > delete b; > use(a); // Error, a is no longer valid. > > Now, these classes may be broken - I did not design them and can not > change them on a source level - but avoiding these situation are pretty > easy in C++, because of the way the classes are used (B is a sort of a > container for A, and it does make sense). > > > However, say I have java code like this, where the classes have been > exposed using the private data fields: > > var B = new B(); > var a = b.getA(0); // From this point on, b is never referenced > > /// code, here > /// The JS decides to GC b > print( a ); // UPS! a contains a pointer to an object embedded in b, > // that is now gone! > > > How do I solve this problem? > > Basically I want to say to the GC: "Do not clean B before a have been > cleaned". > > I have thought about Rooting b in a, but you can have many a's coming > out from b at the same time: > > var B = new B(); > var a = b.getA(0); > var anothera = b.getA(1); > > I don't think there is an easy way to us GC_AddRoot to that? Or rather, > if I call GC_RemoveRoot, when a is finalized, I have the problem that > anothera needs b to live on. > > I want to say to the GC: "Do not clean B before a and another a have > been cleaned" > > From reading the docs, it seems to me, that one perhaps should make a > and another a properties of b? So, I should set a and anothera as > properties of b, whenever b.getA(int) returns an a? > > Does that sound right? > > Any help will be greatly appriciated. A pointer to some docs about how > to use the SpiderMonkey GC "right" would be also be appreciated. > > Thanks in advance, > > Mads > .