C++ Std queue and vector performance - c++

I've been working with graphs lately, and I am looking into returning a path from a graph. The path needs to be returned as a std vector containing all of the nodes with the starting node first.
I've been looking at two options:
- use the slow vector insert method to add the nodes at the front of the vector
- use a deque to add the nodes to the front (push_front), which is much faster. Then copying the deque to the vector using std::copy
Is there a significant performance boost using one method over the other?

Since you're returning a path, you presumably have an upper bound on its length. Therefore, you can call create a vector, call reserve and later (as #user2079303 writes) call push_back to add vertices to the path.
const auto n = <graph_size>
std::vector<size_t> path;
path.reserve(n)
...
v.push_back(i); // Push whatever you want.
Now the problem is that, at least from the question, it seems like v is in the reversed order. However, you can simply call std::reverse:
std::reverse(std::begin(v), std::end(v));
So, using only a vector:
You're allocating a single data structure instead of two; moreover, using reserve there will be a single memory allocation.
The use of reverse at the end simply replaces the use of copy you would have to do from the deque to the vector.

If you are looking at wrapping a std::vector in a std::queue then the std::queue will push elements to the back of the vector (the fast way).
Even if not however, because a std::vector is contiguous storage, it is possible it will out-perform a std::deque even if you push_font() because it plays well with the CPU cache where shuffling data is fast.
But why not try both and profile the code to see which one performs better?

Related

Can vector be resized bidirectionally?

Is there any function to resize a vector in both directions?Can we manipulate the pointer or the element from where it starts adding new empty elements?
Here is the entire interface of std::vector. It makes it very obvious there's no direct way to do what you ask, although you can reserve and then insert(begin,...) if you really want to (it has linear complexity, so is usually avoided).
The usual advice would be to use std::deque instead, since it's specifically designed for this operation.
Yes, you can insert elements to the front of the vector using insert:
vec.insert(vec.begin(), numer_of_elements_to_insert, {});
Note, however, that front-inserting into a vector is very inefficient, because it will require moving all the current elements in the vector past the newly inserted ones. If you need a double-ended container, look into std::deque.

Keeping constant number of elements in vector

I am trying to figure out the fastest way to keep constant number of elements in vector (or maybe there is some ready-made structure that do it automatically).
In my app I am adding multiple elements to the vector and I need to do it fast. Because of vector's self resizing at some point it is significantly decreasing overall application speed. What I was thinking about is to do something like this:
if(my_vector.size() < 300)
my_vector.push_back(new_element);
else
{
my_vector.pop_front();
my_vector.push_back(new_element);
}
but after first few tests I've realized that it might not be the best solution, because I am not sure if pop_front() and later push_back() doesn't still need to resize at some point.
Is there any other solution for this?
Use a std::queue. Its underlying container is a std::deque, but like a stack a queue's interface is specifically for FIFO operations (push_back, pop_front), which is exactly what you're doing in your situation. Here's why a deque is better for this situation:
The storage of a deque is automatically expanded and contracted as
needed. Expansion of a deque is cheaper than the expansion of a
std::vector because it does not involve copying of the existing
elements to a new memory location.
The complexity (efficiency) of common operations on deques is as
follows:
Random access - constant O(1)
Insertion or removal of elements at the end or beginning - constant O(1)
To implement a fixed-size container with push_back and pop_front and minimal memory shuffling, use a std::array of the appropriate size. To keep track of things you'll need a front index for pushing elements and a back index for popping things. To push, store the element at the location given by front_index, then increment front_index and take the remainder modulo the container size. To pop, read the element at the location given by back_index, and adjust that index the same way you did front_index. With that in place, the code in the question will do what you need.
You just need to reserve the capacity to a reasonable number. The vector will not automatically shrink. So it only will grow and, possibly, stop at some point.
You might be also interested in the resize policies. For example Facebook made a substantial research and created own implementation of the vector - folly::fbvector which has better performance than std::vector

Fastest way to add a deque onto the end of a vector?

This question is about speed.
I am using a function in the openCV libraries (in FaceRecognizer class) which requires the input of a vector. I need to build this vector by combining several deque. Are there any faster ways other than iterating through the deque and pushing back each element to the vector?
Some info about the deque: it is a deque of 15 elements where I continuously push_back and if it has 16+ elements I pop_front. Order matters.
Alternatively I could change the deque's to vectors if that might speed up everything, but from what I understand that will be slow when I delete the first element of the vector when it reaches size 16.
Fastest way to add a deque onto the end of a vector?
Getting the size of the deque is possible in constant time (as for all STL containers), then reserve space in the vector to limit memory management overhead to a single allocation, finally move the elements out of the deque into the vector:
// std::vector v, std::deque d
v.reserve(v.size() + d.size());
std::move(std::begin(d), std::end(d), std::back_inserter(v));
d.clear(); // or reuse in some way
If you intend to append multiple containers to the vector, consider reserveing the complete storage necessary at once.
Watch for std::bad_alloc exceptions if the amount of data is huge. In that case using contiguous storage of a vector isn't ideal.
You could do something like
queue/vector myItem;
// Swap the position to the back, if it's first use 0 if you like
myItem[position].swap(myItem.back());
myItem.pop_back();
Then it's not reallocating the entire list when you remove from the front.

Efficient Input Handling with std::vector buffers

I'm trying to find a fast way to do input but I've learned that using STL for such purposes might be slow.
I have a callback that fires whenever I get Keyboard input.
It creates an object with (int _key, int _state, int _life)
Everytime I receive this callback, I push_back the object to my std::vector;
Every frame I check the top of this vector and remove the "dead" input.
The vector can be polled for whatever input is valid at that moment which means it will be searched frequently.
Optimizations:
-All the memory should be contiguous so although Link Lists are better for dynamic allocation, should I stick with STL's vector? I'm always adding to the top and removing from the bottom so what data struct should I use?
-I was thinking of having a buffer(second vector) that continuously receives new input from the callback, then each frame copy the data from that vector to the top of my active input vector. Since the active vector will be polled, would this increase performance since it won't be wasting time getting added to during the loop?
Basically I'm trying to squeeze as much performance from this vector as possible and I could use some help.
What you are describing, adding data in one end, removing in another, is the archetypical description of a queue. This is implemented in the standard library with the std::queue class.
This queue class is a so-called container adapter, meaning it uses another container for the actual storage. By default it uses std::deque, but that container doesn't keep its data in a contiguous memory area. However you can declare a std::queue with almost any other standard container, like std::vector (which is the only container guaranteed to store data in a contiguous memory area):
std::queue<int, std::vector> my_queue_with_vector;
my_queue_with_vector.push(1);
my_queue_with_vector.push(2);
my_queue_with_vector.push(3);
while (!my_queue_with_vector.empty())
{
std::cout << my_queue_with_vector.top() << '\n';
my_queue_with_vector.pop(); // Remove top element in the queue
}
std::deque makes the best container. It guarantees O(1) pop_front and push_back() and has random access and a good degree (although not completely) of cache behaviour.
But if you absolutely must have complete contiguity, then you'll need to look into a custom circular buffer container (there's one in Boost IIRC), as pop_front() on a vector is rather expensive.
Edit: As another poster has pointed out, keyboard input is so infrequent even for a very fast typist that I find it difficult to believe that this is a bottleneck in your system.
Sounds like you want a std::deque. Adjacents elements are nearly always allocated continuously in memory and it has constant time insertion and removal at begin and end.
Short answer: It doesn't matter. std::vector and std::list can easily handle millions of insert operations per second, but most typists don't type faster than 10 characters per second on a keyboard.
Long answer: push_back and erase are usually very cheap on a vector if the vector is small (< 100) and the copy/swap operations of the objects stored on the vector are cheap. The allocations used to insert into or remove from an std:list are usually more expensive. If it becomes an issue, measure the cost.
An std::deque also has allocations and depending on the implementation is likely more expensive than the vector in your case, if my assumption that your vector rarely if ever contains more than 10 items - all of which are cheap to copy - is correct.

Removing Vector from 2D vector

I have a 2D vector containing 96 blocks of 600 values, which is what I want.
I need to remove (blocks) that do not contain sufficient energy. I have managed to calculate the energy but do not know which way would be better in removing the (blocks) that do not contain enough energy.
In your opinions would it be better to create a temporary 2D vector, that pushed back the blocks that do contain enough energy and then delete the original vector from memory or...
Should I remove the blocks from the vector at that particular position?
I'm assuming you have this:
typedef std::vector<value> Block;
typedef std::vector< Block > my2dVector;
and you have a function like this:
bool BlockHasInsufficientEnergy( Block const& vec );
and you want to remove the Blocks that do not have sufficient energy.
By remove, do you mean you want there to be fewer than 96 Blocks afterwards? I will assume so.
Then the right way to do this is:
void RemoveLowEnergyBlocks( my2dVector& vec )
{
my2dVector::iterator erase_after = std::remove_if( vec.begin(), vec.end(), BlockHasInsufficientEnergy );
vec.erase( erase_after, vec.end() );
}
the above can be done in one line, but by doing it in two what is going on should be more clear.
remove_if finds everything that passes the 3rd argument condition, and filters it out of the range. It returns the point where the "trash" at the end of the vector lives. We then erase the trash. This is called the remove-erase idiom.
Maybe you'd want to use linked list, or just set filtered-out items as NULL's, or mark them with bool member flag, or keep a separate vector of indexes of filtered items (if you have several filters at once this saves memory).
The solution vary on what are the constraints. Do you need random access? How much object copy takes? Etc.
Also you can take a look at the STL code (this is STL's vector, right?) and check if it does what you ask for - i.e. copying a vector data.
It depends, in part, on how you define better in this case. There may be advantages to either method, but it would be hard to know exactly what they are. Most likely, it is probably somewhat "better", in terms of memory and processing performance, to erase the exact positions you don't want from the vector instead of allocating an entirely new one.
It may be better still to consider using a deque or list for that purpose, since they may avoid large reallocations that the vector is likely to make as it tries to keep a contiguous segment of memory.