从队列中弹出不同类型的项目时的运行时开销

时间:2013-10-19 19:55:47

标签: c++

有许多方法可以使容器(例如队列)保存不同类型的对象。 具有std::pair<void*, int>元素的最经典,其中element.first是指向对象的指针,element.second是映射到对象类型。

所有这些方法(我知道)在element.second之后涉及一些运行时开销(例如queue.pop()上的某些开关)以找出下划线对象的类型。

我的问题是:是否可以完全消除此运行时开销?毕竟,在将对象(指向对象的指针)推送到队列之前就已知对象类型。

2 个答案:

答案 0 :(得分:3)

如果您静态地知道元素的类型,则可以创建模板化数据存储:

#include <queue>
#include <utility>

namespace store
{
    template <typename T> struct wrapper { static std::queue<T> data; };
    template <typename T> std::queue<T> wrapper<T>::data;

    template <typename T> void put(T const & x) { wrapper<T>::data.push(x); }

    template <typename T> void put(T && x) { wrapper<T>::data.push(std::move(x)); }

    template <typename T> T get()
    {
        T x  = wrapper<T>::data.back();
        wrapper<T>::data.pop();
        return x;
    }

    template <typename T> bool empty() { return wrapper<T>::data.empty(); }
}

用法:

// push on the queue for decltype(a)
store::put(a);

// push on the Foo-queue
store::put(Foo(1, 'true', false));

// pop from the Bar-queue
if (!store::empty<Bar>()) { auto c = store::get<Bar>(); }

答案 1 :(得分:0)

如果你想隐含开关,我想你必须使用polimorphism(如果类型共享一个公共接口)。使用重载的另一种方法是让对中的第二个元素是指向处理该特定类型的函数的指针,而不是类型标记。如果你使用的是C ++ 11,你甚至可以使用lambda表达式。

第一个选项可以让你得到类似的东西:

class IMyInterface
{
public:
  virtual void handle() = 0;
};

class AClass : public IMyInterface
{
public:
  virtual void handle()
  { /*handles (*this) object*/ }
};

class BClass : public IMyInterface
{
public:
  virtual void handle()
  { /*handles (*this) object*/ }
};

void handle_elements(std::vector<IMyInterface*>& v)
{
  while (!v.empty)
  {
    IMyInterface* obj = v.back();
    v.pop_back();
    obj->handle();
  }
}

而第二个选项是:

typedef void (*handler)(void*);

static void handle_int(void* intptr)
{
  int* iValue = (int*)intptr;
  //Handles iValue
}

static void handle_complex_object(void* ccptr)
{
  ComplexClass* ccValue = (ComplexClass*)ccptr;
  //Handles ccValue
}

void handle_elements(vector<pair<void*, handler>>& v)
{
  while (!v.empty)
  {
    pair p = v.back();
    v.pop_back();
    p.second(p.first);
  }
}

void fill_queue(vector<pair<void*, handler>>& v)
{
  v.push_back(pair<void*, handler>(new int(10), handle_int);
  v.push_back(pair<void*, handler>(new ComplexClass(), handle_complex_object);
}