To improve efficiency of std::vector<T>
, it's underlying array needs to be pre-allocated and sometimes re-allocated. That, however, requires the creation and later moving of objects of type T
with a copy ctor or move ctor.
The problem that I am having is that T
cannot be copied or moved because it contains objects that cannot be copied or moved (such as atomic
and mutex
). (And, yes, I am implementing a simple thread pool.)
I would like to avoid using pointers because:
Is there a way to avoid a level of indirection here?
UPDATE: I fixed some incorrect assumptions and re-phrased the question, based on feedback in comments and answers.
std::move itself does "nothing" - it has zero side effects. It just signals to the compiler that the programmer doesn't care what happens to that object any more. i.e. it gives permission to other parts of the software to move from the object, but it doesn't require that it be moved.
Storing and Accessing Class Objects in a Vector The primary difference in using vectors for storing class objects versus using an array, other than all the differences between vectors and arrays, is how you declare the vector to store class objects. We can use the same Student class definition as shown earlier.
No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.
For the start, std::mutex
can not be copied or moved, therefore you are forced to use some kind of indirection.
Since you want to store mutex in a vector, and not copy it, I would use std::unique_ptr
.
vector<unique_ptr<T>>
does not allow certain vector operations (such as for_each)
I am not sure I understand that sentence. It is perfectly possible to do range for :
std::vector< std::unique_ptr< int > > v; // fill in the vector for ( auto & it : v ) std::cout << *it << std::endl;
or to use std algorithms :
#include <iostream> #include <typeinfo> #include <vector> #include <memory> #include <algorithm> int main() { std::vector< std::unique_ptr< int > > v; v.emplace_back( new int( 3 ) ); v.emplace_back( new int( 5 ) ); std::for_each( v.begin(), v.end(), []( const std::unique_ptr< int > & it ){ std::cout << *it << std::endl; } ); }
That requires however the creation of objects of type T with a copy ctor.
That is not entirely right, as of C++11, if you use the constructor of std::vector
which will default construct a number of elements, then you don't need to have a copy or move constructor.
As such, if no threads are added or deleted from your pool, you can then just do:
int num = 23; std::vector<std::mutex> vec(num);
If you want to add or delete things dynamically, then you have to use an indirection.
std::vector
+ std::unique_ptr
as already proposedstd::deque
, that allows you to neatly use it with range based for loops or std-algorithms and avoids all indirections. (Which only allows additions)std::list/forward_list
this solution is similar to number one, however it has the additional benefit of easier usage with range based for and algorithms. It's probably the best if you are only accessing the elements sequentially as there is no support for random-access.Like this:
std::deque<std::mutex> deq; deq.emplace_back(); deq.emplace_back(); for(auto& m : deq) { m.lock(); }
As a final note, std::thread
is of course moveable, so you can use std::vector
+ std::vector::emplace_back
with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With