Thread: Dynamic Lists? Is it possible? Is it a logical solution?

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    58

    Dynamic Lists? Is it possible? Is it a logical solution?

    To start, I will present my problem, and then explain the possible solutions I can't seem to implement properly.

    Problem: I have a basic struct (shown below), that all objects inherit from. I also have a simple derived class that I want to add to a static list on creation.

    However, I would like for there to be separate lists created for each object type.

    So, I would like a list to be created for every type of object...even new ones that someone creates, which eliminates the possibility of creating a static list of objects to add to for every object type.

    Code:
    struct Base
    {
    protected:
        int ID;
    }
    Code:
    class Derived1
    {
    public:
        Derived(int x):ID(x) {}
    };
    Code:
    class Derived1
    {
    public:
        Derived(int x):ID(x) {}
    };

    Using this structure, how could I dynamically create lists for the derived1 and derived2 classes?

    I thought that I could create a list of lists of type T, like so:
    Code:
    template<class T> static List<List<T>> Lists
    then populate it like this:
    Code:
    if(Lists.Contains(List<Derived1>)
    {
        Lists.Get(List<Derived>).Add(derived1);
    }
    else
    {
        Lists.Add(List<Derived>());
        Lists.Get(List<Derived>).Add(derived1);
    }
    however...this is pure psuedocode, and apparently you can't create an list of lists of type T....
    ...does anyone know a standard or intelligent solution to this? Creating dynamic lists, for every type created, to store and track every custom object in your program...


    Seems like something that would be incredibly useful. Let me know if you guys find anything!

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> and apparently you can't create an list of lists of type T

    Of course you can.

    >> if(Lists.Contains(List<Derived1>)

    I believe dynamic_cast might be what you're looking for (just be sure to make the base class destructor virtual).

    >> does anyone know a standard or intelligent solution to this?

    I suppose you could create a base class (a template, perhaps) that adds the address of the object to the list in the constructor. But I'm still not 100% sure what exactly you're wanting to do here. It might be a good idea to post an example that actually compiles.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    58
    Alright...well I have to cut certain things out. But here is what I'm working with:


    Base Object:
    Code:
    #ifndef _OBJ_H_
    #define _OBJ_H_
    #include <new>
    #include "linkedlist.h"
    #include "activeobjects.h"
    class Object
    {
    public:
    	~Object(void) {/*ActiveObjects::List.Add(LinkedList<this>().Add(this));*/}
    protected:
    	Object(void) {}
    	int _ID;
    };
    #endif
    Static List
    Code:
    #ifndef _ACTIVEOBJECTS_H_
    #define _ACTIVEOBJECTS_H_
    #include "linkedlist.h"
    class ActiveObjects
    {
    public:
    	static LinkedList<LinkedList<void**>*> List;
    private:
    	ActiveObjects(void);
    };
    //template<typename type> LinkedList<LinkedList<type*>*> ActiveObjects::List = LinkedList<LinkedList<type*>*>();
    #endif

    What I'm attempting to do, is simply make it so that whenever you initialize an object that inherits from "Object", it will immediately be stored in a list of pointers so I can keep track of their ID and the actual object to see if it is being deleted properly...
    I just thought it would be a nice way to make debugging much easier.

    So...I could do a list like this: List<Object> objects;
    But that wouldn't organize them well, and anyone who uses this code, would have to create a new list in the source whenever they create a new object (if I choose to use different lists for each object type).

    I thought that doing a list of lists of type T would work just fine. But you can't throw a generic type into a generic class that requires a type.

    For example:
    Code:
    template <class T> List<T> objects;
    won't compile.
    Code:
    List<Object> objects
    will compile.
    Code:
    List<void*> objects
    <-- this is more along the lines of what I'm trying to do. But I would really like to hear everyone elses opinion on this.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    I think this comes down to what you think you mean when you say "see if it is being deleted properly". If the objects are just being created, then they will be destroyed when they go out of scope with or without you doing anything about it. If you're doing a lot of new'ing and worried about forgetting to delete, then that's a concern, but that has nothing to do with the class and everything to do with being less forgetful. (And in that case, then I would think a plain list or set of Object* would suffice -- it doesn't seem like you would need to sort that by type.) If there's lots of memory management going on inside the object, then that would probably have to be done by the object, not by the class.

  5. #5
    Registered User
    Join Date
    Apr 2008
    Posts
    58
    Very true, tabstop.

    However, I was forced to overload the new and delete keywords, and do a few other things that make me need to check the memory.

    As far as the lists go, a better example is this....

    I have a bullet list, and a player list...
    the bullets inherit from object, and so does player.
    When bullet is initialized, it goes into a list for bullets.
    When player is initialized, it goes into a list for players.
    The lists then number their IDs respective to their position in the list.
    This way, Player #1 would have an ID of 1, and bullet #1 would have an ID of one as well.

    This allows me to select the appropriate list and iterate through the collection that I need, rather than iterating through 50,000 objects to get to my players.

    This is the main reason I have wanted to create this list of lists.

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Here's a possible starting point:

    Code:
    #include <list>
    #include <vector>
    #include <iostream>
    
    class Tracked
    {
        public:
        
        typedef std::list< Tracked* >
            list_type;
        
        Tracked( int id = 0 )
        : id( id )
        {
            std::cout << "Tracked(" << id << ") at address: " << this << std::endl;    
        /*
            Make sure we aren't already on the list
        */
            if( get( ) == objects.end( ) )        
                objects.push_back( this );
        }
        
        virtual ~Tracked( void )
        {
            std::cout << "~Tracked(" << id << ") at address: " << this << std::endl;
            objects.erase( get( ) );
        }    
    
    /*
        Just a helper function
    */    
        list_type::iterator get( void )
        {
            return std::find( objects.begin( ), objects.end( ), this );
        }
        
        int
            id;
            
        static list_type
            objects;
            
        protected:
    
        Tracked( Tracked const& rhs );    
    };
    
    Tracked::list_type
        Tracked::objects = Tracked::list_type( ); 
    
    class Foo : public Tracked
    {
        enum
        {
            type_tag = 3114
        };
        
        public:
        
        Foo( void )
        : Tracked( type_tag )
        {    }
        
        Foo( Foo const& )
        : Tracked( type_tag )
        {    }    
    };
    
    class Bar : public Tracked
    {
        enum
        {
            type_tag = 2012
        };
    
        public:
        
        Bar( void )
        : Tracked( type_tag )
        {    }
        
        Bar( Bar const& )
        : Tracked( type_tag )
        {    }    
    };
        
    int main( void )
    {
        std::vector< Foo >
            foos( 3 );
        std::vector< Bar >
            bars( 4 );        
        std::cout << "-- Listing tracked objects -- " << std::endl;    
        for
        ( 
            Tracked::list_type::const_iterator 
                seq = Tracked::objects.begin( ), 
                fin = Tracked::objects.end( );
            seq != fin;
            ++seq    
        )
        {
            std::cout << "Address: " << *seq << " (Type: " << ( *seq )->id << ")" << std::endl;
        }
        std::cout << "-- End of listing -- " << std::endl;    
        return 0;
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Registered User
    Join Date
    Apr 2008
    Posts
    58
    Okay...I have to admit...that is a pretty piece of code :P

    That is very very similar to what I'm doing...or at least trying to do haha.
    The only issue is that it appears that if I have 10000 bullets on the screen, and a new player emerges, it will have to iterate through all those bullets to find him...


    I REALLY thank you for that nice chunk of code though! Any ideas on how to make it more dynamic for my purposes?

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Here's a little more generic approach:

    Code:
    #include <list>
    #include <vector>
    #include <iostream>
    
    template < typename Type >
    class Tracked
    {
    	public:
    	
    	typedef std::list< Type* >
    		list_type;
    	
    	Tracked( void )
    	{
    		init( );
    	}
    	
    	Tracked( Tracked const& )
    	{
    		init( );
    	}		
    	
    	virtual ~Tracked( void )
    	{
    		std::cout << "~Tracked() at address: " << this << std::endl;
    		objects.erase( get( ) );
    	}	
    
    /*
    	Just some helper functions
    */	
    	void init( void )
    	{
    		std::cout << "Tracked() at address: " << this << std::endl;	
    	/*
    		Make sure we aren't already on the list
    	*/
    		if( get( ) == objects.end( ) )		
    			objects.push_back( ( Type* )this );	
    	}
    
    	typename list_type::iterator get( void )
    	{
    		return std::find( objects.begin( ), objects.end( ), ( Type* )this );
    	}
    	
    	static list_type
    		objects;
    };
    
    template < typename Type >
    typename Tracked< Type >::list_type
    	Tracked< Type >::objects = typename Tracked< Type >::list_type( ); 
    
    class Player : public Tracked< Player >
    {	};
    
    class Munition : public Tracked< Munition >
    {	};
    
    class Bullet : public Munition, Tracked< Bullet >
    {	};
    	
    template< typename Type >	
    void print_listing( std::string const& name )
    {
    	std::cout << "-- Listing tracked " << name << " -- " << std::endl;	
    	for
    	( 
    		typename Tracked< Type >::list_type::const_iterator 
    			seq = Tracked< Type >::objects.begin( ), 
    			fin = Tracked< Type >::objects.end( );
    		seq != fin;
    		++seq	
    	)
    	{
    		std::cout << "Address: " << *seq << std::endl;
    	}
    	std::cout << "-- End of listing for " << name << " -- " << std::endl;
    }	
    	
    int main( void )
    {
    	std::vector< Munition >
    		munitions( 1 );		
    	std::vector< Bullet >
    		bullets( 2 );		
    	std::vector< Player >
    		players( 3 );
    	print_listing< Munition >( "munitions" );		
    	print_listing< Bullet >( "bullets" );
    	print_listing< Player >( "players" );		
    	return 0;
    }
    Last edited by Sebastiani; 07-23-2009 at 12:57 AM. Reason: bugfix
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    58
    very nice and elegant!
    I can certainly see how I could use this! Thank you very much!
    If anyone else has any other solutions, I would love to see them as well!


    (The main thing I'm trying to avoid is the bit in main where you create the list; Since I was trying to let a list populate itself with lists depending on the object type being created.)
    Last edited by arcaine01; 07-23-2009 at 01:01 AM.

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    There was actually a subtle bug in the code I posted. Fixed.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> The main thing I'm trying to avoid is the bit in main where you create the list; Since I was trying to let a list populate itself with lists depending on the object type being created.

    The list isn't being created in main, those are just vectors to hold a few test objects. You could have declared 6 separate objects and the effect would be the same.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. two-dimensional dynamic array of pointers to classes
    By Timo002 in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 06:18 AM
  2. From Python's Linked Lists to Dynamic Arrays
    By hexbox in forum C Programming
    Replies: 3
    Last Post: 01-26-2005, 03:14 PM
  3. Help creating lists of pointers
    By The_Kingpin in forum C Programming
    Replies: 2
    Last Post: 12-11-2004, 08:10 PM
  4. Question about Linked lists of lists
    By hear_no_evil in forum C Programming
    Replies: 2
    Last Post: 11-08-2004, 02:49 AM
  5. Linked Lists 101
    By The Brain in forum C++ Programming
    Replies: 5
    Last Post: 07-24-2004, 04:32 PM