Igor
Igor

Reputation: 9

Runtime overhead on popping different type items from a queue

There are bunch of methods to make containers (e.g. queue) to hold objects of different types. The most classical to have an std::pair<void*, int> element, where element.first is the pointer to the object and element.second mapped to the object type.

All those method (which I know) involves some runtime overhead (e.g. some switch on element.second) after queue.pop() to find out the type of the underline object.

My question is: is it possible eliminate this runtime overhead completely? After all, the object type has been known just before the object (pointer to the object) pushed to the queue.

Upvotes: 0

Views: 76

Answers (2)

Giulio Franco
Giulio Franco

Reputation: 3230

If you want to make the switch implicit, I guess you have to use polimorphism (if the types share a common interface). Another way to use overloading is to have the second element of the pair be a pointer to a function that handles that specific type, rather than a type tag. If you're using C++11, you can even use lambda expressions.

The first option would get you to something like:

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();
  }
}

while the second option would be:

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);
}

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 477444

If you know the type of the element statically, you can make a templated data store:

#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(); }
}

Usage:

// 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>(); }

Upvotes: 3

Related Questions