You can use std::vector<std::mutex>
directly, because the type requirements when using standard library containers are restricted to only those required by the functions called on them.
Once you have constructed a std::vector<std::mutex>
with some elements, only the operations that might add new elements or erase old ones require the value type to be movable. Accessing the vector elements and moving the vector itself are not problems.
Constructing the vector with vec(num)
works, because it only default constructs a known number of elements. It can constructs the new elements in-place in the storage.
The constructor used by vec(numB, numA)
actually takes as arguments the number of elements and a const
lvalue reference to an object of the value type. It does not take constructor arguments to construct the new elements from in-place. Instead when you pass it numA
, numA
is implicitly converted to a A
(via the non-explicit
constructor) and a reference to that A
is passed to the constructor.
The constructor is then specified to copy-construct the vector elements from the passed object.
But because std::vector<std::mutex> vec;
is not copyable, A
isn't either and so it fails.
There is however another constructor for std::vector
that can construct objects without copy/move constructor: The constructor taking an iterator range. However, to use it we first need to construct an iterator range with the constructor arguments to pass to the vector elements' constructor:
auto args = std::vector(numB, numA);
vec = {args.begin(), args.end()};
Alternatively, with explicit types:
std::vector<int> args(numB, numA);
vec = std::vector<A>(args.begin(), args.end());
If you want to do this in the member-initilizer-list you can delegate this to a member function or lambda and return
instead of vec =
.
The iterator range constructor construct the vector elements in-place by converting *it
and if the iterators are forward iterators (as is the case above), then the constructor does not require any move operations.
Note that vec.assign(args.begin(), args.end())
does not work, since assign
is allowed to use assignment instead of construction.