container of unrelated T in c++

試著忘記壹切 提交于 2019-12-11 05:18:58

问题


If I have the following hypothetical class:

namespace System
{
    template <class T>
    class Container
    {
    public:
        Container() { }
        ~Container() { }
    }
}

If I instantiate two Containers with different T's, say:

Container<int> a;
Container<string> b;

I would like to create vector with pointers to a and b. Since a and b are different types, normally this wouldn't be possible. However, if I did something like:

std::stack<void*> _collection;
void *p = reinterpret_cast<void*>(&a);
void *q = reinterpret_cast<void*>(&b);
_collection.push(a);
_collection.push(b);

Then later on, I can get a and b back from _collection like so:

Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());

My question is, is this the best way for storing a collection of unrelated types? Also would this be the preferred way of storing and retrieving the pointers from the vector (the reinterpret cast)? I've looked around and seen that boost has a nicer way of solving this, Boost::Any, but since this is a learning project I am on I would like to do it myself (Also I have been curious to find a good reason to use a reinterpret_cast correctly).


回答1:


While it is possible to cast to void * and back, the problem is knowing which type you're popping. After all, you give the example:

Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());

However, if you were to accidentally do:

Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());

Now you've got pointers to the wrong type, and will likely see crashes - or worse.

If you want to do something like this, at least use dynamic_cast to check that you have the right types. With dynamic_cast, you can have C++ check, at runtime (using RTTI), that your cast is safe, as long as the types being casted (both before and after) have a common base type with at least one virtual method.

So, first create a common base type with a virtual destructor:

class ContainerBase {
public:
  virtual ~ContainerBase() { }
};

Make your containers derive from it:

template <typename T>
class Container : public ContainerBase {
// ...
}

Now use a std::stack<ContainerBase *>. When you retrieve items from the stack, use dynamic_cast<Container<int> >(stack.pop()) or dynamic_cast<Container<string> >(stack.pop()); if you have the types wrong, these will check, and will return NULL.

That said, heterogeneous containers are almost always the wrong thing to be using; at some level you need to know what's in the container so you can actually use it. What are you actually trying to accomplish by creating a container like this?




回答2:


Consider boost::any or boost::variant if you want to store objects of heterogeneous types.

And before deciding which one to use, have a look at the comparison:

  • Boost.Variant vs. Boost.Any

Hopefully, it will help you to make the correct decision. Choose one, and any of the container from the standard library to store the objects, std::stack<boost::any>, std::stack<boost::variant>, or any other. Don't write your own container.

I repeat don't write your own container. Use containers from the standard library. They're well-tested.



来源:https://stackoverflow.com/questions/7150475/container-of-unrelated-t-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!