Jump to content
  • Advertisement
Sign in to follow this  
_goat

Storing the type of a class

This topic is 4682 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm pretty sure you can't, the way I want it: To be able to store the type of a certain class to later be used, for example:
NOTE: Of course this doesn't work

SomeClass<typeid(MyClass)>::StaticMethod("42?");
I think we both know that it's not going to work, and you can't do that with typeid no matter what you call. So my question is, is there a way to do this (doubtfull), and if not, what is the best way to get around this problem? Note that the stuff I'm using uses template classes and static members, meaning that for the most part, polymorphism doesn't work.

Share this post


Link to post
Share on other sites
Advertisement
Okay, I'll outline what I'm trying to do.

I'm trying to create a memory management system. I've put the bare essentials in the box below.


class _AFactory_Base
{
public:
static unsigned long * getReference(void * object)
{
return mObjectMap[object];
}
static void setAutoDelete(void * object, bool auto_delete) {...}
virtual void remove(void * object) = 0;
protected:
static map<void*, unsigned long*> mObjectMap;
};

template <class T> class AFactory : public _AFactory_Base
{
public:
T * add(T * object)
{
mObjectMap[object] = new unsigned long(1);
return object;
}
void remove(void * object)
{
delete (T*)object;
// and then remove from list
}
};




Like I said, the bare essentials. This setup works in conjucture with a smart pointer "AP", which increments and decrements the unsigned long, and calls remove() when appropriate. The reason no AFactory has its own class (as they did in the beginning to improve speed), is because I need to
support polymorphism, because:


// allocates
CETextureDX * texture = AFactory<CETextureDX>::create(new CETextureDX);

// now has reference count of 1 (didn't show that implementation)
AP<CETextureDX> ap_texture = texture;

// now both ap_texture and ap_texture2 point to the same
// unsigned long (with value of 2)
AP<CETextureDX> ap_texture2 = texture;

// BORK! The call is being made to CITexture
AP<CITexture> ap_Itexture = ap_texture;




The problem lies in that if ap_Itexture is the last to fall out of scope, then it'll make the remove() call to CITexture, which will delete it as a CITexture, rather than its actual CETextureDX. So I wanted to somehow store the type of the objects being held in the mObjectMap (and thus making the _AFactory_Base the only class needed, so I'd probably change that to AFactory itself). So I could say stuff like

// map::iterator i
delete (i->type_of_class)i->first;

and get the correct deletion happening. I'm reasonably certain there's no way to actually store the TYPE of a class. Yes to type information, but no to the actual type. So I'm wondering, is there a way to trick it to get the destructor happening and the deletion correct?

Share this post


Link to post
Share on other sites
Give your classes virtual destructors and the right destructor should be called no matter what kind of pointer is used to delete it. (Unless you cast to void *)

Share this post


Link to post
Share on other sites
I'm fairly certain you're speaking of polymorphism, where the objects keep tabs on their own class details. I'll give you a quick primer (in c++):

class Base {
Base();
virtual void DoSomething();
};
class Fork : public Base{
Fork();
virtual void DoSomething();
};
class Branch : public Base {
Branch();
virtual void DoSomething();
};

Three classes, two variants and a base class. Now, lets say I do something like this:

Base * object[3];
object[0] = new Base();
object[1] = new Fork();
object[2] = new Branch();
object[0]->DoSomething(); /* calls Base::DoSomething */
object[1]->DoSomething(); /* calls Fork::DoSomething */
object[2]->DoSomething(); /* calls Branch::DoSomething */

This'll work as expected, because even though the type of all three objects is Base, the Fork and Branch objects have whats called a "vtable" which keeps track that they have different definitions of DoSomething.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Give your classes virtual destructors and the right destructor should be called no matter what kind of pointer is used to delete it. (Unless you cast to void *)


Yes, that's the problem - I have. And I've been wracking my brains trying to figure out an alternative or different algorithm, and the best I've gotten so far is a system that deletes everything at the end, but there's no destructors called. Which could be pretty important if sockets and such are concerned. I'd write you a little UML to simplify it all if I could be bothered.

So I either need to store the type of the class, or find something different. I tried having two std::maps, one in each AFactory as a map<T*, unsigned long*> and the shared one in _AFactory_Base (of map<void*, unsigned long*>), but the same problem exists in that if a AP<CITexture> is the last to fall out of scope and call remove, AFactory<CITexture>::remove() will be called, and try and delete it as a CITexture. PLUS it'll still be hanging around in AFactory<CETextureDX>, just waiting to be deleted again and causing errors.

So yeah, either there's something in the std I don't know about (possible), or I have to keep thinking about this for another few days (likely).

Share this post


Link to post
Share on other sites
I'd argue that your class has absolutely nothing to do with Factories, but well, if that's how you want to call it...


class AFactory
{
public:
static unsigned long * getReference(void * object)
{
map<void*, record_type>::iterator itor;
itor = mObjectMap.find(object);

if(itor == mObjectMap.end())
return 0;
else
return &itor->second.first;
}

static void setAutoDelete(void * object, bool auto_delete) {...}

template<class T> static T* add(T* object)
{
if(mObjectMap.find(object) == mObjectMap.end())
mObjectMap[object] = make_pair(1, &destroy<T>);

return object;
}

static void remove(void * object)
{
map<void*, record_type>::iterator itor;
itor = mObjectMap.find(object);

if(itor != mObjectMap.end())
{
itor->second.second(object);
mObjectMap.erase(itor);
}
}

private:
typedef void destructor_type(void*);
typedef pair<unsigned long, destructor_type*> record_type;

static map<void*, record_type> mObjectMap;

template<class T> static void destroy(void* object)
{
delete (T*)object;
}
};

Share this post


Link to post
Share on other sites
Haha yes, it started out as something completely different, I just never got rid of the factory party. Although they do churn out objects...

As for function pointers, now I feel a little stupid. For the longest time I was mucking around trying to see if there was a way to get a pointer to the class that had created each pointer (and storing that), so that stored class could call remove(). Never though of getting a pointer to the method itself. I guess it's one of the downsides of using (and therefore learning) C++ style programming over C style. You miss out on the gritty powerful stuff. Carmak must have been resisting using C a hell of a lot during Doom3.

Thanks very much guys - reliable memory management. Bliss.

Share this post


Link to post
Share on other sites
Quote:
Original post by _goat
Although they do churn out objects...


No, they don't. They only register those objects you passed to them.

Quote:
Never though of getting a pointer to the method itself.


Watch out, pointers to non-static member functions are very, very different beasts.

Quote:
I guess it's one of the downsides of using (and therefore learning) C++ style programming over C style. You miss out on the gritty powerful stuff.


And instead, you spend time reinventing the wheel. Imagine if you hadn't known about the standard map class?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!