Archived

This topic is now archived and is closed to further replies.

stefu

Garbage Container in C++

Recommended Posts

stefu    120
What's best way to do garbage container in c++. No smaprtpointers. Just keep track of referencecount.
      
list<Object *> alive;
list<Object *> dead;

class Object 
{
private:
    int ref_c;

public:
    Object() : ref_c(1) { alive.push_back(this); }
    virtual ~Object() {}

    void delRef() { 
        ref_c--;
        if (!ref_c) {
            alive.remove(this);
            dead.push_back(this);
        }
    void addRef() { ref_c++; }
}
    
This should keep track of objects that are alive and that should be deleted. Then frequently I need to delete all object in dead-list and empty it.
  
void emptyCarbage()
{
    list<Component*>::iterator it = dead.begin();
    list<Component*>::iterator last = dead.end();
    while (it != last) {
        delete (*it++);
    };
    dead.empty();
}
      
What do you think about this? Is it possible/smart to create separate thread for emptying dead objects periodically? I haven't yet implemented this because I have quite a big system I'd like to have clean and safe carbage collection. So I don't want to do this before I know it works ok. Thanks for any ideas Edited by - stefu on March 19, 2002 7:55:35 AM

Share this post


Link to post
Share on other sites
SabreMan    504
Personally, I think this is a somewhat misguided attempt to instil GC into C++. GC is a hugely complex undertaking, and you are simplifying it to the extreme. My first piece of advice would simply be don''t do it! If you feel you must do this, then Google for existing GC systems.

The technique you are using makes it very easy to bypass the GC system, as it requires everything to inherit from Object (one of my pet hates in C++). You''re requiring C++ programmers using your framework to adhere to a rigorous and unnatural discipline just to make your GC work.

Also, what happens in the following sort of scenario:


std::vector *p_v = new std::vector;


?

Share this post


Link to post
Share on other sites
stefu    120
I think you are overshooting what I meant.
It''s not meant to be for all objects, like it''s in Java.

Just for example for GUI compoenents to be able to have multiple references, keep track of reference count and delete components when they''r not required anymore.

Share this post


Link to post
Share on other sites
Ziphnor    122
Have you looked at the reference counting pointer that is implemented in the the tutorial here on gamedev.net? I made my own implementation based on that tutorial(ie copy paste, change a few names and im gonna use it for the exact same thing you are, handling when to delete GUI components(and other components that are thrown around between modules).
The reference counting pointer they implement actually handles all reference counting, so you dont have to depend on yourself or other programmers to remember calling removeRef.
The only thing it cant handle is circular references, ie if Object1 holds a ref to Object2 and object2 has one to Object1 they will never get deleted, but that shouldnt be an issue with GUI components(at least now the way mine are implemented).

The URL is http://www.gamedev.net/reference/articles/article1060.asp
have a look at it.

[edited by - ziphnor on March 19, 2002 9:16:41 AM]

Share this post


Link to post
Share on other sites
Ziphnor    122
Ive played a little around with it, and now im trying to find ways to "break" it, ie obtaining the pointer from the ref.counting pointer and copying it without the ref being counted.

So far it surprised me that i could pass a managed pointer like this to a method that took a normal pointer.
I think it may have have defined a conversion from managed pointer to normal pointer. But what is to stop the method called from doing bad things(like copying the real pointer) now that it has the pointer?

EDIT: He defines the following conversions:

  
/** Conversion operators */
operator T* () const { return m_ptr; }
operator const T* () const { return m_ptr; }

They seem a bit unsafe to me, sure it allows me to pass a managed pointer instead of a normal one, but then the pointer is lose, and just as unsafe as before, isnt it?

EDIT END <-

I was expecting to change methods like paint(GraphicsManager* gm) to paint(ManagedPointer gm).(i would probably make a typedef)

Well, ill give you a chance to have a better look at it, so we can find out exactly how useful it is.

Personally i understand templates and operator overloading well enough, but operator overloading confuses me a litle with regards to return values.

[edited by - ziphnor on March 19, 2002 10:08:36 AM]

Share this post


Link to post
Share on other sites
stefu    120
This is actually smart pointer. While ago I looked at one implementation of smartpointers and it was so messy I ignored them as not being usable. This seems quite a clean.

quote:
Original post by Ziphnor
I was expecting to change methods like paint(GraphicsManager* gm) to paint(ManagedPointer gm).(i would probably make a typedef)


That''s what I was too thinking, to use typedefs


  
class Test : public RefCntObject
{
};
typedef RefCntPointer<Test> sTest;

// usage

sTest p;


What would be good naming conventions. post-''s'' for ''smart'' to know it''s smartpointer?

Share this post


Link to post
Share on other sites
stefu    120
/** Conversion operators */
operator T* () const { return m_ptr; }
operator const T* () const { return m_ptr; }

Where do you actually need these?

Share this post


Link to post
Share on other sites
Ziphnor    122
Just had a look in the book "C++ for real programmers" by Jeff Alger which provides a similar implementation, but he never defines such conversion operators.

I guess they are provided for the managed pointer to be directly compatible with code that wants a normal pointer, but doing so kind of makes the whole exercise futile....

Anyway, Jeff Alger has one more trick, he makes the constructor private and instead provides a make() method that returns a managed pointer, so there is now way at all to retrieve a pointer to the managed object(perhaps apart from dereferencing it and then using & to obtain it), but that can be avoided by not supporting the dereference operator *).

As for your typedef im doing something similar, just using mp(ManagedPointer) as prefix.

Share this post


Link to post
Share on other sites
stefu    120

    
I actually developed problem with it.

// Before I had this

class Component
{
// add any kind of component

void add(Component *c);
}

class Panel: public Component
{
};
class Button : public Component
{
};

I could add buttons
Panel *p = new Panel;
Button *b = new Button;
p->add(b);

But this doesn't work with smartpointer :(
class Component
{
// add any kind of component

void add(sComponent c);
void add(sButton c); // Do need separate function for each component???

}
typedef RefCntPointer<Component> sComponent;

class Panel: public Component
{
};
typedef RefCntPointer<Button> sButton;
class Button : public Component
{
};
typedef RefCntPointer<Button> sButton;

sPanel p = new Panel;
sButton b = new Button;

p->add(b); // need add-procedure for each kind of component???







[edited by - stefu on March 19, 2002 10:50:51 AM]

Share this post


Link to post
Share on other sites
Ziphnor    122
Whats wrong with declaring the derived classes like this:

sComponent b = new Button();

sComponent p = new Panel();

That was what i was intending to anyway.
Or maybe i misunderstood you?

Share this post


Link to post
Share on other sites
stefu    120
Indeed you misunderstod.

I can''t pass sButton as sComponent in
void add(sComponent c).

I need
void add(sButton b); for button
void add(sLabel l); for label
...


Share this post


Link to post
Share on other sites
DrPizza    160
quote:
Indeed you misunderstod.

I can''t pass sButton as sComponent in
void add(sComponent c).

I need
void add(sButton b); for button
void add(sLabel l); for label
...

Of course, a class containing a pointer to a derived class isn''t convertible to a class containing a pointer to a base class.

You need to say is-a, not has-a.

Share this post


Link to post
Share on other sites
Ziphnor    122
quote:

Indeed you misunderstod.



Now im confused, are we agreed that declaring:

    
ManagedPointer<Component> c = new Button(); will work?

(because a Button is also a Component, because if not i dont understand anything

And if you have an method

  
add(ManagedPointer<Component> comp)

then it can accept the button made above?

Then i really fail to see the problem(or am i being stupid?)

Its perfectly understandable that

   
ManagedPointer<Button>
wont work because its a different class than

  ManagedPointer<Component> 
, and one is not derived from the other.
Like the above post says, its has-a when you need is-a

EDITED: Forgot about the problem with "<" and ">"
EDITED AGAIN: code tags doesnt help...


[edited by - ziphnor on March 19, 2002 3:50:31 PM]

Share this post


Link to post
Share on other sites
stefu    120

  
ManagedPointer<Component> c = new Button(); will work?

Yes, it works.

But this doesn't directly:
ManagedPointer<Button> b = new Button();
ManagedComponent<Component> = b; // !!!


but these works:
ManagedComponent<Component> = (Button *)b;
ManagedComponent<Component> = (Component *)b;

maybe I'm missing one operator but can't find it out what kind of :(



[edited by - stefu on March 19, 2002 4:11:49 PM]

Share this post


Link to post
Share on other sites
stefu    120

  
void add(ManagedComponent<Component> c)
{
// ...

}

ManagedComponent<Button> b = new Button;

add((Button*)b); // works

add((Component*)b); // works too


add(b); // doesn't work!!!


I'll continue tomorrow, trying to find a solution. zzzZZ



[edited by - stefu on March 19, 2002 4:18:27 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Goto www.boost.org and take a look at their libraries, they have lots of very useful things such as good random number generators, regular expressions matches and tokenizers. They also have three smart pointers, boost::shared_ptr being the one you''ll probably want. Many parts of these libraries are being considered for the next C++ standard, just to hint at their quality and that they won''t become unsupported. These libraries are essential if you use STL and many experienced C++ users use them.

Avoid reinventing the wheel.

Share this post


Link to post
Share on other sites
Ziphnor    122
(is use "[" instead of "<" here )
Why do you insist on
ManagedComponent[Button] c1 = new Button()
instead of
ManagedComponent[Component] c2 = new Button();??

Even with normal pointers i would do this:
Component* c = new Button();
instead of
Button* b = new Button();

The whole idea of the all the components are that they are Components.

Converting between c1 and c2 is of course not possible possible, the 2 classes are only related in that they have members that are related.

Share this post


Link to post
Share on other sites
stefu    120
quote:
Original post by Ziphnor
(is use "[" instead of "<" here )
Why do you insist on
ManagedComponent[Button] c1 = new Button()
instead of
ManagedComponent[Component] c2 = new Button();??

Even with normal pointers i would do this:
Component* c = new Button();
instead of
Button* b = new Button();

The whole idea of the all the components are that they are Components.

Converting between c1 and c2 is of course not possible possible, the 2 classes are only related in that they have members that are related.



This is not possible:

  
ManagedPointer<Component> b = new Button();
b->setButtonState(DOWN); / !! component doesn't have setButtonState, it's button's property.

Btw, it is possible with the SmartPointer (link somewhere above)

AP: Thanks, I'll take a look at there

[edited by - stefu on March 19, 2002 12:09:28 AM]

[edited by - stefu on March 19, 2002 12:10:06 AM]

Share this post


Link to post
Share on other sites
Ziphnor    122
But before you had an add method that takes a Component* and if you give it a Button*, the Button* will be converted to Component* and you wont be able to set the button state anyway inside the add method or if you choose to store the Component*.

Ill have a look at the smart pointer you linked to, but right now i dont see any problems with this one.....

EDIT: The implementation at http://www.codeproject.com/cpp/smartptr.asp
does seem pretty smart(doesnt require inheritance from a base class), ill have to look closer at it...

[edited by - ziphnor on March 20, 2002 6:44:03 AM]

Share this post


Link to post
Share on other sites
Ziphnor    122
Damn, i decided to use the smartpointer from the code project, but i cant get it to work in VS.NET

this little test program:

  
#include "SmartPtr.h"

int main()
{
return 0;
}


Results in this when compiled:

------ Build started: Project: SmartPtr, Configuration: Debug Win32 ------

Compiling...
test.cpp
d:\test\test\SmartPtr\SmartPtr.h(195) : error C2146: syntax error : missing '';'' before identifier ''m_CriticalSection''
d:\test\test\SmartPtr\SmartPtr.h(196) : see reference to class template instantiation ''CSyncAccessRep'' being compiled
d:\test\test\SmartPtr\SmartPtr.h(195) : error C2501: ''CSyncAccessRep::CRITICAL_SECTION'' : missing storage-class or type specifiers
d:\test\test\SmartPtr\SmartPtr.h(195) : error C2501: ''CSyncAccessRep::m_CriticalSection'' : missing storage-class or type specifiers
d:\test\test\SmartPtr\SmartPtr.h(322) : error C2244: ''CSyncAccess::__ctor'' : unable to match function definition to an existing declaration
definition
''CSyncAccess::CSyncAccess(const CSyncAccess::REP> &)''
existing declarations
''CSyncAccess::CSyncAccess(const CSyncAccess::REP *)''
''CSyncAccess::CSyncAccess(const CSyncAccess &)''
d:\test\test\SmartPtr\SmartPtr.h(324) : error C2954: template definitions cannot nest

Build log was saved at "file://d:\test\test\SmartPtr\Debug\BuildLog.htm"
SmartPtr - 5 error(s), 0 warning(s)


---------------------- Done ----------------------

Build: 0 succeeded, 1 failed, 0 skipped


And the sample project supplied on the website give similar errors:

------ Build started: Project: SmartPtrDemo, Configuration: Debug Win32 ------

Compiling...
SmartPtrDemo.cpp
d:\test\SmartPtr.h(322) : error C2244: ''CSyncAccess::__ctor'' : unable to match function definition to an existing declaration
definition
''CSyncAccess::CSyncAccess(const CSyncAccess::REP> &)''
existing declarations
''CSyncAccess::CSyncAccess(const CSyncAccess::REP *)''
''CSyncAccess::CSyncAccess(const CSyncAccess &)''
d:\test\SmartPtr.h(324) : error C2954: template definitions cannot nest

Build log was saved at "file://d:\test\Debug\BuildLog.htm"
SmartPtrDemo - 2 error(s), 0 warning(s)


---------------------- Done ----------------------

Build: 0 succeeded, 1 failed, 0 skipped


What compiler do you use? And do you have any ideas what could cause this?

Share this post


Link to post
Share on other sites
stefu    120
"What compiler do you use? And do you have any ideas what could cause this? "
I'm on linux and gcc.

I had to remove much there to make it work, since it has those multithreaded stuff for windows.
If you want just the Smart pointer stuff then remove all the Sync* parts that seems to give errors for you.


I found a problem with the SmartPointer, because

    
Foo *f = new Foo();
SmartPointer<Foo> f1 = f;
SmartPointer<Foo> f2 = f; // This is illegal!



This means that I can't use this in class procedure.

  
SmartPointer<Foo> f = this;

I need to derive my classes from SmartObject that has the ref_cnt in itself.



[edited by - stefu on March 20, 2002 10:24:32 AM]

Share this post


Link to post
Share on other sites
Ziphnor    122
Arghh, im still having loads of problems with it....
Seems it defines some hash method that wont work with one of my declarations. Damn it, i hate this kind of crap. And on top of that it doesnt include the files it needs....

Maybe i should take a look at the ones at boost instead, or just go back to the ManagedPointer i had before....

Share this post


Link to post
Share on other sites
stefu    120
I don''t either use the SmartPointer, my own instead I made. The pros using self-made pointer is that you know what it does anfd how and you can make changes

The boost indeed seemd to have much good things too.

Share this post


Link to post
Share on other sites