如何创建一个可以容纳任意类型指针的容器?

How do I make a container that holds pointers of any type

本文关键字:类型 任意 指针 创建 何创建 一个      更新时间:2023-10-16

这可能看起来很傻,但我想创建一个容器来保存任何类型的指针,这样我就可以将每个指针存储在那里,然后很容易地删除它们。我试着:

vector<void*> v;
v.push_back(new Dog());
v.push_back(new Cat());
cout <<  v[0]; // prints mem address
cout <<  v[1]; // prints another mem address
cout << *v[0]; // compiler yells at me

但是显然你不能解引用void指针。有没有一种方法可以使任何类型的指针的泛型容器,而不必使每个类扩展一个超类称为"对象"或什么?

你可以实现一个模板类的指针包装器,该模板类继承了一个通用的基类,并将其放置到容器中。下面的内容:

class pointer_wrapper_base
{
public:
  virtual void delete_pointee()=0;
protected:
  void *m_ptr;
};
template<class T>
class pointer_wrapper: public pointer_wrapper_base
{
public:
  pointer_wrapper(T *ptr_) {m_ptr=ptr_;}
  virtual void delete_pointee()
  {
    delete (T*)m_ptr;
  }
};

一旦你有了这个类,你就可以使用多变体类,例如,它就像变体类,但是所有不同的变体都有一个共同的基类。我有一个实现在这里,如果你想看看:http://sourceforge.net/p/spinxengine/code/HEAD/tree/sxp_src/core/utils.h(搜索poly_pod_variant):

  std::vector<poly_pod_variant<pointer_wrapper_base> > x;
  x.push_back(pointer_wrapper<Cat>(new(Cat)));
  x[0]->delete_pointee();

或者,如果您对包装器的动态分配没有问题,那么您当然可以将指向pointer_wrap_base的指针存储到向量中,例如

std::vector<std::unique_ptr<pointer_wrapper_base> > x;
x.push_back(std::unique_ptr<pointer_wrapper_base>(new(pointer_wrapper<Cat>)(new Cat)));
x[0]->delete_pointee();

研究一下使用Boost的一些类,比如Boost::any, http://www.boost.org/doc/libs/1_55_0/doc/html/any.html和它们的示例代码http://www.boost.org/doc/libs/1_55_0/doc/html/any/s02.html

或者,看看Boost的变体。

一般来说,学习Boost。

c++有一个静态类型系统。这意味着在编译时必须知道所有表达式的类型。问题的解决方案取决于你打算如何处理这些对象。

选项1:让CatDog来自一个类

如果所有对象都有一个公共接口,并且可以使它们从一个类派生,那么这是有意义的。

std::vector<std::unique_ptr<Animal>> vec; // good practice - automatically manage 
                                          // dynamically allocated elements with
                                          // std::unique_ptr
vec.push_back(std::make_unique<Dog>()); // or vec.emplace_back(new Dog());
vec.push_back(std::make_unique<Cat>()); // or vec.emplace_back(new Cat());
std::cout << *v[0];

选项2:boost::any

如果类型不相关,这是有意义的。例如,您存储int s和类的对象。显然,你不能使int从你的类派生。所以您使用boost::any来存储,然后将其强制转换回对象的类型。如果转换为不相关的类型,则抛出boost::bad_any_cast类型的异常。

std::vector<boost::any> vec;
vec.push_back(Dog());
vec.push_back(25);
std::cout << boost::any_cast<int>(vec[1]);

同时,指针。"我想妥善管理我的内存"的解决方案是"不要使用new delete"这些工具可以帮助你做到这一点,没有特别的顺序:

  • std::string代替以空结尾的字符串
  • std::vector<T>代替new T[]
  • std::unique_ptr<T>代替原始指针指向多态对象
  • …或std::shared_ptr<T>,如果你分享它们

count <*((狗*)v[0]);

我在这里假设你的Dog类是可字符串化的,否则你会得到不同类型的错误,但是你的类型转换问题应该通过(Dog *)类型强制转换来解决。