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

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.

Related

How to insert a new element at the beginning of std::vector without any copy and default constructing overhead if I know the number of elements?

I need to fill from end some preallocated uninitialized memory region. I want to use std::vector, but I don't want inserting each new element at the beginning of vector forcing it to make unnecessary copies and another overhead. Is there any way to achieve this with std::vector?
Inserting an element at the beginning of a non empty std::vector always implies copying plus allocation overhead if the new size of the vector will be greater then the capacity of the vector. This is by design, since a std::vector has its uninitialized memory at the end of it or to quote THE C++ standard:
26.3.11.1 Class template vector overview [vector.overview] 1 A vector is a sequence container that supports (amortized) constant time insert
and erase operations at the end; insert and erase in the middle take
linear time.
Knowing the number of elements is irrelevant in this regard, as long as you want to stick to std::vector. You can use it to minimize the allocation overhead by using reserve() i.e. increasing the capacity before hand, but as long as you are inserting not at the end of the vector, you will have copying overhead.
Consider using a std::deque if you don't know the total number of elements, otherwise use an std::array.
Use rbegin and rend instead of begin and end, then push_back adds elements to the "beginning" of the reversed view.

Using vector to minimize heap allocations causes seg faults

Within a function, I have created a vector with generous amounts of space to which I push a runtime determined amount of objects(Edge). Other objects, however, maintain pointers to the Edges within the vector. Occasionally the entire program seg faults because a pointer becomes invalid, and I suspect that this happens when the vector reaches capacity and reallocates, thereby invalidating the memory addresses.
Is there any way around this? Or perhaps is there another solution to grouping together heap allocations?
Note: that the primary motivation for this is to minimize heap allocations, for this is what is slowing down my algorithm. Initially I had vector<Edge *> and every element added was individually allocated. Batch allocation increased the speed dramatically, but the vector method described here invalidates pointers.
Your code example, as requested:
This is the vector I declare as a stack var:
vector<Edge> edgeListTemp(1000);
I then add to it as such, using an rvalue overload:
edgeListTemp.push_back(Edge{edge->movie, first, second});
Node objects keep pointers to these:
first->edges.push_back(&edgeListTemp.back());
second->edges.push_back(&edgeListTemp.back());
Where edges is declared as follows:
std::vector<Edge *> edges; /**< Adjacency list */
There are several possible solutions:
if you already know the maximum number of elements in advance, do a reserve over the vector from the start; elements won't be reallocated until you reach that size;
if you don't know the maximum number of elements/don't want to preallocate the maximum size for performance reasons but you only add/remove elements from the end (or from the start) of the vector, use an std::deque instead. std::deque guarantees that pointers to elements aren't invalidated as long as you only push/pop from front/back;
std::list guarantees to never invalidate references to elements, but it introduces several serious performance penalties (no O(1) addressing, one allocation for each node);
if you want to ignore the problem completely, add a layer of indirection, and store into the vector pointers to elements allocated over the heap; even better, make a vector of std::shared_ptr and always use it to keep references to the elements; this obviously has the disadvantage of needing one allocation for each element, which may or may not be acceptable, depending on your use case.
A std::deque does not move elements once added, so iterators and references are stable as long as you don't delete the referenced element.
Like std::vector, std::deque offers random access iterators. Random access into a deque is a little slower than std::vector, but still O(1). If you need stable references, the slight slow-down is probably acceptable.
Alternatively, instead of the pointer to the element, you could keep a reference to the vector and an index into the vector.

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

C++ Std queue and vector performance

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?

will stl deque reallocate my elements (c++)?

Hi I need an stl container which can be indexed like a vector but does not move old elements in the memory like a vector would do with resize or reserve (Unless I call reserve once at the beginning with a capacity enough for all elements, which is not good for me). (Note I do address binding to the elements so I expect the address of these elements to never change). So I've found this deque. Do you think it is good for this purpose? Important: I need only pushback but I need to grow the container on demand in small chunks.
std::deque "never invalidates pointers or references to the rest of the elements" when adding or removing elements at its back or front, so yes, when you only push_back the elements stay in place.
A careful reading of the documentation seems to indicate that so long as you insert at the beginning or the end it will not invalidate pointers, and invalidating pointers is a sign that the data is being copied or moved.
The way it's constructed is not quite like a linked list, where each element is allocated individually, but as a set of linked arrays presumably for performance reasons. Altering the order of elements in the middle will necessitate moving data around.