A data structure that can contain multiple data types

As in the title, I am looking for some kind of data structure that will allow me to store in it any class that I need at that time. For instance:

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 / etc functions.
I want one of them, because I am trying to create an โ€œinvisibleโ€ memory management system that simply requires the class to inherit from my memory manager class and everything will work automatically.
Here is an example of how I want the code to look like this:

 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 will help to understand what exactly 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'm currently working on creating some kind of zombie snake of a linked list class that uses template nodes to associate any type of class with any other type of class. I still donโ€™t know how I earned, but I would like to be spared blood, sweat and tears (and hair) in order to understand how to make it work.

+4
source share
4 answers

You have a common base class for all of your several types. Keep the data structure in the pointers of your base class type.

+4
source

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

+3
source

Can any hybrid specialization of templates and double dispatch? Something like that:

 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 is unknown during compilation of the operations of elements in the container or they are distributed between modules that are not compiled together, you can use dynamic_cast instead. You define an "IFooHandler" class with a pure virtual method, "HandleFoo", which takes a foo pointer. You must make Operation :: Process virtual and get your working class from both Operation and IFooHandler and implement the operation in HandleFoo (). Your Foo :: OperateOn method will be dynamic_cast (pOperation), and if the result was not null, it will call HandleFoo () in the IFooHandler pointer, which you will get from dynamic wrapping. Otherwise, you would call the generic Operation :: Process, and it would have non-type behavior.

+1
source

Using std::vector<T*> should work. Indeed, a new class will be created for each instance of MemoryManaged . This means that MemoryManaged<Foo> and MemoryManaged<Bar> will be completely different types. Therefore, the static container member will not be common to these two classes . It will be as if you had the following two 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 two instances.

Of course, this solution assumes that MemoryManaged will always be used using CRTP, as you described in your question. In other words, 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 }; 
0
source

Source: https://habr.com/ru/post/1315021/


All Articles