Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store different data types in one list? (C++)

I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.

I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.

class Property {      Property(std::string name);      virtual ~Property();       std::string m_name; };  class PropertyBoolean : Property {      PropertyBoolean(std::string name, bool data);       bool m_data; };  class PropertyFloat : Property {      PropertyFloat(std::string name, float data);       float m_data; };  class PropertyVector : Property {      PropertyVector(std::string name, std::vector<float> data);       std::vector<float> m_data; }; 

Now I can store all kinds of properties in a

 std::vector<Property*> 

and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.

Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?

I do not have access to Boost.

like image 983
hasdf Avatar asked Aug 24 '10 17:08

hasdf


People also ask

How do I store different data types in a list?

A list in Python CAN contain different types of data. Each item in the list is separated by a comma and the entire list is enclosed in square brackets [] . To add a new item to the list, just edit the list starting before the closing bracket. Add a comma and the new item.

Can we store different data types in linked list in C?

Yes, it's allowed as long as the list is declared as List<Object> or List<Serializable> , which both String and Integer extend/implement.

Can a list store different types?

Question: Is it possible to store n number of lists of various types in a single generic list? Answer: Yes, by creating a list of list objects.

Can we store different data types in array in C?

Yes we can store different/mixed types in a single array by using following two methods: Method 1: using Object array because all types in . net inherit from object type Ex: object[] array=new object[2];array[0]=102;array[1]="csharp";Method 2: Alternatively we can use ArrayList class present in System.


2 Answers

C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.

class Property { public:     Property(const std::string& name) //note: we don't lightly copy strings in C++       : m_name(name) {}     virtual ~Property() {} private:     std::string m_name; };  template< typename T > class TypedProperty : public Property { public:     TypedProperty (const std::string& name, const T& data)       : Property(name), m_data(data); private:     T m_data; };  typedef std::vector< std::shared_ptr<Property> > property_list_type; 

Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:

void f() {   std::vector<Property*> my_property_list;   for(unsigned int u=0; u<10; ++u)     my_property_list.push_back(new Property(u));    use_property_list(my_property_list);    for(std::vector<Property*>::iterator it=my_property_list.begin();                                       it!=my_property_list.end(); ++it)     delete *it; } 

That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.

The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".

In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.

Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.

like image 185
sbi Avatar answered Sep 19 '22 13:09

sbi


A lower-level way is to use a union

class Property   union {     int int_data;     bool bool_data;     std::cstring* string_data;   };   enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;   // ... more smarts ... }; 

Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.

EDIT: Some more code to give an example of usage.

Property car = collection_of_properties.head(); if (car.data_type == Property::INT_PROP) {   printf("The integer property is %d\n", car.int_data); } // etc. 

I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:

Property::Property(bool value) {   bool_data = value;   data_type = BOOL_PROP; } 
like image 21
Grumdrig Avatar answered Sep 22 '22 13:09

Grumdrig