Hi, I believe this is my first posting to DaniWeb, so thanks very much in advance for your time!

I have been doing some searching and I am not sure of a definitive answer to the following problem. I am attempting to make a class that can store a set of pointers to generic data, and what I had started to do was use a void* for each piece of data, contained in a data item wrapper class. That allows me to do the following, where _pData is a void*:

pSomeItem->_pData = pSomeClassPointer;
// ...other code here...
pDifferentClassPointer = reinterpret_cast<SomeClass*>(pSomeItem->_pData);

Unfortunately, some brief searching has left me uneasy about whether C++ really guarantees that all pointers to objects (i.e. SomeClass) and primitives (i.e. long int, char, etc.) will be the same size. I would guess that this is usually the case on 32-bit and 64-bit Intel systems, and I am not writing this code for obscure or embedded systems, but I would still like to know the correct way to do this if possible, and any sort of references if a C++ standard or some other source guarantees it.

From my reading I have gathered that function/method pointers may well have different sizes, and that is not a problem for me since I only want to store pointers to data.

If the above is NOT the case, does anyone have a suggestion for a solution? The only solution I can think of so far to store a pointer to a generic piece of data is to use templates and declare the data collection to use that type.

Thanks again for your time!

Recommended Answers

All 9 Replies

Can you tell us the application? Maybe someone will have a suggestion. Storing things as a void* always sounds like a bad plan to me...

I have a generic collection class that can have specific implementations (i.e. a linked list representation, or perhaps a hashmap). I know that I could probably use a premade class or standard library collection, but I figured it was a good learning experience since I am just doing this for fun.

I am not trying to copy data and store it in the collection, merely store any pointer type in the collection. I suppose the "right" answer may end up being "use templates", but I was hoping to avoid that syntax. :P

do you want to store different types of data in this container at the same time?

Container stuff;
int a = 5;
char b = 'b';
double c = 3.14;
stuff.add(&a);
stuff.add(&b);
stuff.add(&c);

do you want to store different types of data in this container at the same time?

Container stuff;
int a = 5;
char b = 'b';
double c = 3.14;
stuff.add(&a);
stuff.add(&b);
stuff.add(&c);

Not at the same time, so I'd like to be able to do something like:

MyCollection coll;
MyCollection coll2;

DataPtr* p1;
DataPtr* p2;
AnotherClassPtr* p3;
AnotherClassPtr* p4;

coll.add(p1);
coll.add(p2);
coll2.add(p3);
coll2.add(p4);

I already spent the time to start converting it to use templates. Changing the code itself was pretty trivial, so I am just working through the syntax for declaring and using the classes/methods now. This will probably work, since I only want to be able to store a single type of data in each collection...but if anyone has advice for making a general collection that could store heterogeneous pointers, feel free to share! :)

Templates are diffidently the way to go then.

void* is usually used to simulate generics in C. In C++, template were made to remove
this bad method. Since you are using C++, definitely, ditch void* and use templates.

Unfortunately, some brief searching has left me uneasy about whether C++ really guarantees that all pointers to objects (i.e. SomeClass) and primitives (i.e. long int, char, etc.) will be the same size.

I would have thought (I don't have my standard to hand to check) that C++ makes the same guarantees as C in this respect. That is it doesn't guarantee anything except that if you cast a pointer to type T to void * and cast it back to T* it will still be valid.

It certainly does not guarantee they will be the same, and in fact I have worked on platforms where they have not been the same size and even if they are the same size it doesn't guarantee that the bits in the pointers mean the same thing.

This means that code such as this

long l = 5;

// C
char *pc = (char*)&l;

// C++
char *pc = reinterpret_cast<char*>(&l);

Rely on platform defined behaviour and are strictly speaking non-portable.

I assume C++ also makes a few guarantees about casting up and down a class hierarchy.

Well after a few hours of (re)learning template syntax, especially the details about using static methods in template functions and having subclasses of templatized classes, I have my refactored code building and it seems to work. :P Thanks for the input, everyone! I'm still not sure about how one would do a generalized collection that could accept different types of pointers though, if one needed to do that, something like:

pCollection->AddItem(XClassPtr);
pCollection->AddItem(YClassPtr);

I suppose that I will leave this not marked as solved in case anyone wants to add input on that subject. Otherwise, I can mark it solved if that is preferred.

It is unlikely you would want a container that you hold a generic absolutely anything. On the other hand you might want a container that held several different sub-types of a type (for instance several different types of vehicle).

And that is what class hierarchies, inheritance and polymorphism are for (well one of the things). You declare a hierarchy with your base class holding the interface and any common information and in your container you hold hold pointers to base base. Because there are base class pointers you can actually store (a pointer to) any object within the inheritance tree.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.