Re: [ROOT] TRef, Streamers et Clone()

From: Rene Brun (Rene.Brun@cern.ch)
Date: Mon Apr 21 2003 - 13:11:54 MEST


Hi Alexis,

I have fixed this special case with TRef when cloning an object.
The fix is in CVS.
Note that you do not need a Streamer function to handle this case.
You do not have to set the parent. This is done automatically.
Thanks for reporting this case and giving a simple example.

Rene Brun

On Fri, 
18 
Apr 2003, Mignon Alexis wrote:

> Hi René,
> 
> I use the version 3.05/00 on a linux platform
> 
> | root [11] c3->GetParent()
> | (class TestClass*)0x899c098
> | root [12] c
> | (class TestClass*)0x899c098
> 
> That's not what i want . I would like c3->GetParent() to return the 
> address of c2. With the automatically generated streamer it returns 0, 
> i would have thought it would return the address of c.
> 
> So I've customized the streamer :
> 
>  void TestClass::Streamer(TBuffer &R__b)
>  {
>     // Stream an object of class TestClass.
> 
>    UInt_t R__s, R__c;
>    if (R__b.IsReading()) {
>       Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) {
> } TObject::Streamer(R__b);
>       R__b >> fList;
> 
> ////// that's what i've added //////////
>       TIter next(fList);
>       TestClass2*c2;
>       while( (c2=(TestClass2*)next()) ){
>         c2->SetParent(this);
>       }
> /////////////////////////////////////////////
>       R__b.CheckByteCount(R__s, R__c, TestClass::IsA());
>    } else {
>       R__c = R__b.WriteVersion(TestClass::IsA(), kTRUE);
>       TObject::Streamer(R__b);
>       R__b << fList;
>       R__b.SetByteCount(R__c, kTRUE);
>    }
>  }
> 
> i thought - naively - that it would then set the TRef to the address 
> of the object being build through the streamer.
> 
> So what must i do to correctly set the TRefs of the objects in the list 
> so that they actually point to their real parent ?
> can it be done through the streamer ?
> 
> Le Jeudi 17 Avril 2003 17:56, vous avez écrit :
> | Hi Alexis,
> |
> | Unfortunately, you do not indicate which version of Root and OS.
> | I cannot reproduce your problem. Using your .H and .C files, I have
> | created a shared lib mignon.so, then run the following session:
> |
> | root [0] .L mignon.so
> | root [1] TestClass* c=new TestClass;
> | root [2] c->Add("first");
> | root [3] c->Add("second");
> | root [4] c->Add("third");
> | root [5] c.ls()
> | OBJ: TestClass  TestClass       test class : 0 at: 0x899c098
> | root [6] TestClass* c2=(TestClass*)c->Clone();
> | root [7] c2.ls()
> | OBJ: TestClass  TestClass       test class : 0 at: 0x89a37d0
> | root [8] TestClass2* c3=(TestClass2*)c2->GetList()->First();
> | root [9] c3
> | (class TestClass2*)0x89d2368
> | root [10] c3.ls()
> | OBJ: TestClass2 first   testclass2 : 0 at: 0x89d2368
> | root [11] c3->GetParent()
> | (class TestClass*)0x899c098
> | root [12] c
> | (class TestClass*)0x899c098
> |
> | AS you can see, results seem to be correct.
> |
> | Rene Brun
> |
> | Mignon Alexis wrote:
> | > Hello,
> | >
> | > I have a problem with some circular refernces when i try to make a
> | > clone of an object.
> | >
> | > i have for instance 2 objects :
> | >
> | > /////////////////// TestClass.H ///////////////////////
> | >
> | > #ifndef __TestClass__
> | > #define __TestClass__
> | >
> | > #include <TList.h>
> | > #include "TestClass2.H"
> | > class  TestClass2;
> | > class  TestClass : public TObject {
> | > protected :
> | >   TList *fList; // -> list
> | >
> | > public :
> | >   TestClass();
> | >   ~TestClass();
> | >
> | >   TestClass2* Add(const Char_t *name);
> | >   TList* GetList() const;
> | >   ClassDef(TestClass,1) //test class
> | > };
> | >
> | > inline TList*TestClass::GetList() const{
> | >   return fList;
> | > }
> | >
> | > #endif
> | > \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
> | > and
> | > /////////////// TestClass2.H ///////////////////////////
> | > #ifndef __TestClass2__
> | > #define __TestClass2__
> | >
> | > #include <TNamed.h>
> | > #include <TRef.h>
> | > #include "TestClass.H"
> | >
> | > class TestClass;
> | > class TestClass2 : public TNamed{
> | > protected:
> | >   TRef fClassTest; // back reference
> | >
> | > public:
> | >   TestClass2();
> | >   TestClass2(const Char_t* name, TestClass* tc);
> | >   ~TestClass2();
> | >
> | >   TestClass* GetParent();
> | >   void SetParent(TestClass*c);
> | >
> | >   ClassDef(TestClass2,1) //test class 2
> | >
> | > };
> | >
> | > inline TestClass* TestClass2::GetParent(){
> | >   return (TestClass*)fClassTest.GetObject();
> | > }
> | >
> | > #endif
> | >
> | > \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
> | >
> | > with the default streamer when i do
> | >
> | > TestClass* c=new TestClass;
> | > c->Add("first");
> | > c->Add("second");
> | > c->Add("third");
> | >
> | > TestClass* c2=(TestClass*)c->Clone();
> | >
> | > TestClass2* c3=(TestClass2*)c2->GetList()->First();
> | >
> | > then
> | > c3->GetParent() returns the null pointer (why not the pointer to c
> | > ?)
> | >
> | > to set the parent member of TestClass2
> | >
> | > i've modified the streamer of TestClass so that it does a
> | > class2->SetParent(this) for each object in its list.
> | >
> | > but then
> | >
> | > c3->GetParent() returns the pointer to c instead of c2 .
> | >
> | > What must i do in order to get the good parent pointer to the clone
> | > of the first object
> | >
> | > this is the source code for the 2 classes :
> | >
> | > ////////////////////////// TestClass.C ////////////////////////////
> | >
> | > #include "TestClass.H"
> | > #include <TCollection.h>
> | >
> | > ClassImp(TestClass);
> | >
> | > TestClass::TestClass(){
> | >   fList=0;
> | > }
> | >
> | > TestClass::~TestClass(){
> | >   if(fList) {
> | >     fList->Delete();
> | >     delete fList;
> | >   }
> | > }
> | >
> | > TestClass2* TestClass::Add(const Char_t*name){
> | >   if (!fList) fList=new TList;
> | >   TestClass2*c=new TestClass2(name, this);
> | >   fList->Add(c);
> | >   return c;
> | > }
> | > void TestClass::Streamer(TBuffer &R__b)
> | > {
> | >    // Stream an object of class TestClass.
> | >
> | >    UInt_t R__s, R__c;
> | >    if (R__b.IsReading()) {
> | >       Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) {
> | > } TObject::Streamer(R__b);
> | >       R__b >> fList;
> | >       TIter next(fList);
> | >       TestClass2*c2;
> | >       while( (c2=(TestClass2*)next()) ){
> | >         c2->SetParent(this);
> | >       }
> | >       R__b.CheckByteCount(R__s, R__c, TestClass::IsA());
> | >    } else {
> | >       R__c = R__b.WriteVersion(TestClass::IsA(), kTRUE);
> | >       TObject::Streamer(R__b);
> | >       R__b << fList;
> | >       R__b.SetByteCount(R__c, kTRUE);
> | >    }
> | > }
> | >
> | > \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
> | >\\\\\
> | >
> | > and
> | >
> | > ////////////////////////// TestClass2.C
> | > //////////////////////////// #include "TestClass2.H"
> | >
> | > ClassImp(TestClass2);
> | >
> | > TestClass2::TestClass2(){
> | >   fClassTest=0;
> | > }
> | >
> | > TestClass2::TestClass2(const Char_t *name, TestClass* tc)
> | >
> | >   : TNamed(name,"testclass2"){
> | >
> | >   fClassTest=tc;
> | > }
> | >
> | > TestClass2::~TestClass2(){
> | > }
> | >
> | > void TestClass2::SetParent(TestClass *c){
> | >   fClassTest=c;
> | > }
> | > \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
> | >\\\\ --
> | > Alexis Mignon
> | > GANIL
> | > Bd Henri Becqurel
> | > 14076 CAEN Cedex 5
> | > France
> | > tel: +(33) (0)231454680
> | > e-mail : mignon@ganil.fr
> 
> 



This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:11 MET