Manu343726
Manu343726

Reputation: 14174

.data() equivalent for std::queue

My question is simple: Its possible to obtain a pointer to the underlying storage of a std::queue container adapter?

I'm working on some simulations using SFML for rendering, and I use the draw() method of the SFML render target (sf::RenderTarget) to draw the entire bunch of data. That method has a C-like interface expecting a pointer to the data and a std::size_t with the number of elements to draw.

Since the data is stored in a queue for some purposes, I will be glad if there is some way to get that pointer to the queue underlying storage instead of copying the data to a vector.
I know that std::queue adapts the container std::deque by default, but I don't know how that circular buffer is implemented and if its data is contiguous (So I can extract a pointer to the data directly).

EDIT: Performance

Looking at the answers bellow, let me note that I'm not using std::deque because its fancy queue-like interface, but because I really need fast queueing. Of course I can use std::vector. If performance wasn't the point here I would have used push_back()and erase( begin() ) of vector. But what I need is fast queueing and a way to move the data of that queue to the render target efficiently. Of course if the balance queueing vs effort to draw it goes to the draw side, I will use std::vector.

Upvotes: 7

Views: 1740

Answers (2)

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42899

The most intuitive thought would be to use a std::vector as the underling container of your std::queue to assure contiguous memory and then by taking the address of std::queue::front to access the contiguous storage of the wrapped std::vector.

However, as @Blastfurnace correctly noted std::vector doesn't have a pop_front member function and when you were going to call std::queue::pop the program would blast.

Also as already mentioned, std::queue normally requires as its underlying container, a container like std::deque or std::list. Due to their structural traits these containers are the most suitable because they can pop efficiently their front element. However, due to its contiguous memory std::vector lacks of such versatility.

Also, if use of a container with contiguous memory is something that would boost significantly your application it's better and more straightforward to use a std::vector.

However, and for the record, you could also do the following hack in order to circumvent the lack of std::vector's pop_front member function. You could define a class that inherits from std::vector and implement the pop_front member function like the example below:

#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>

template<class T, class Alloc = std::allocator<T>>
class queuevec : public std::vector<T, Alloc> {
public:
  void pop_front() {
   if(!this->empty()) this->erase(this->begin());
  }
};

int main() { 
  std::queue<int, queuevec<int>> Q;

  for(int i(0); i < 10; ++i) Q.push(i);

  Q.pop();

  int *t = &(Q.front());
  std::for_each(t, t + Q.size(), [](int const i){ std::cout << i << " "; });
  std::cout << std::endl;
}

LIVE DEMO

Upvotes: 1

Roddy
Roddy

Reputation: 68033

Is it possible to obtain a pointer to the underlying storage of a std::queue container adapter?

Short answer: No.

std::queue requires a SequenceContainer type, like std::deque or std::list. Neither of these guarantee contiguous storage, so there's no concept of a pointer to the underlying storage.

If they used contiguous circular buffers, this would either impose a fixed size on the container, or incur large cost (like std::vector can) when the container needs to be resized.

You could look at using a boost::circular_buffer instead.

Upvotes: 10

Related Questions