views:

127

answers:

4

Like the title says, I'm looking for some kind of data structure which will allow me to store any type of class into it that I need at the time. For example:

Foo *foo = new Foo();
Bar *bar = new Bar();
someContainer.push_back( foo );
someContainer.push_back( bar );
someContainer.access( 0 )->doFooStuff();
someContainer.access( 1 )->doBarStuff();

Ideally, as I showed there, it would also allow me to access the contents and use their functions/etc.
I want one of these as I am attempting to create an "invisible" memory management system that just requires a class to inherit my memory manager class, and everything will work automagically.
Here is an example of what I want the code to look like:

template< class T >
class MemoryManaged
{
   MemoryManaged()
   {
      container.push_back( this );
   }
   void *operator new()
   {
       // new would probably be overloaded for reference counting etc.
   }
   void operator delete( void *object )
   {
       // delete would most definitely overloaded
   }
   T &operator=( T &other )
   {
      // = overloaded for reference counting and pointer management
   }

   static SomeContainer container;
}

class SomeClass : public MemoryManaged< SomeClass >
{
   // some kind of stuff for the class to work
};
class AnotherClass : public MemoryManaged< AnotherClass >
{
   // more stuff!
};

I hope that my code helps make clear what exactly it is I want to do. If someone knows some kind of already-built data structure that would allow me to do this, that would be awesome. Otherwise, I am currently working on building some kind of shambling zombie of a linked list class that uses templated nodes in order to link any type of class to any other type of class. I still have no idea how I'd get it to work yet, and I would love to be spared the blood, sweat, and tears (and hair) it would take to figure out how to make it work.

+2  A: 

Have a common base class for all of your multiple types. Have the data structure hold onto pointers of your base class's type.

Gunslinger47
This actually sparked an idea in my head for what to do. If I create a base class that inherits into the templated class, and the base class collects pointers, it could work. Something like: template< class T > MemoryManage : public BasePointerHolder or something.
Freezerburn
That's what I was getting at. You'll want that to be `public virtual` inheritance, though, if you plan to support classes with multiple inheritance.
Gunslinger47
+3  A: 

Take a look at boost::any and boost::variant.

Nikolai N Fetissov
+1  A: 

Would some hybrid of template specialization and double-dispatch help? Something like this:

class IContainable;
class Operation
{
public:
   template<class ElementType> void Process(ElementType* pEl) {
      // default is an unrecognized type, so do nothing
   }
};

class IContainable
{
public:
    virtual void OperateOn(Operation* pOperation) = 0;
};


class Foo : public IContainable
{
public:
    int GetFooCount() { return 1; }
    virtual void OperateOn(Operation* pOperation);
};

// specialization of the operation for Foo's
template <> void Operation::Process<Foo>(Foo* pFoo)
{
     std::cout << pFoo->GetFooCount() << std::endl; 
}

void Foo::OperateOn(Operation* pOperation)
{
   pOperation->Process(this);
}

int main()
{
    typedef std::vector<IContainable*> ElementVector; 
    ElementVector elements;
    // configure elements;
    Operation oper;
    for(ElementVector::iterator it = elements.begin(); 
         it != elements.end(); it++)
    {
        (*it)->OperateOn(&oper);
    }
}

If the list of types in the container isn't known at compile time of the operations of the elements on the container, or they are distributed across modules that are not compiled together, then you could instead use dynamic_cast. You'd define a "IFooHandler" class witha pure virtual method called "HandleFoo" that takes a foo pointer. You'd make Operation::Process virtual and have your operation class derive from both Operation and IFooHandler and implement the operation in HandleFoo(). Your Foo::OperateOn method would dynamic_cast(pOperation) and if the result was non-null, it would call HandleFoo() on the IFooHandler pointer you get from the dynamic cast. Otherwise you'd call the generic Operation::Process and it would have some non-type-specific behavior.

David Gladfelter
This seems like some very interesting stuff. I will take a proper look at everything you wrote tomorrow, when it isn't past midnight.
Freezerburn
A: 

Using a std::vector<T*> should work. Indeed, a new class will be created for each instantiation of MemoryManaged. This means that MemoryManaged<Foo> and MemoryManaged<Bar> will be totally different types. Consequently, the static member container will not be common to these two classes. It will be as if you had the two following classes:

class MemoryManagedFoo
{
    MemoryManagedFoo()
    {
        //Here, you know that 'this' is a Foo*
        container.push_back(this); //ok, we add 'this' to a container of Foo*
    }

    static std::vector<Foo*> container;
};

class MemoryManagedBar
{
    MemoryManagedBar()
    {
        //Here, you know that 'this' is a Bar*
        container.push_back(this); //ok, we add 'this' to a container of Bar*
    }

    static std::vector<Bar*> container;
};

As you can see, the static member is not shared by the two instantiations.

Of course, this solution assumes that MemoryManaged will always be used using CRTP, as you described in your question. In other word, this code will work:

class Foo : public MemoryManaged<Foo> { };

but not this one:

class Foo : public MemoryManaged<Bar> 
{
    // Here, 'container' is a 'vector<Bar*>' and 'this' is a Foo * --> problem
};
Luc Touraille
This would work, and I've even thought about this. However, what I was attempting to do was create a universal list holding all allocated objects. At the end of the day, it would tell me which objects were still hanging around in memory, allowing me to recognize that I have memory leaks easily, instead of splitting the list up between who knows how many different compile-time template classes. Putting the static in my example code was a mistake that I didn't realize until now.
Freezerburn