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