I have a class field which is a std::vector. I know how many elements I want this vector to contain: N. How do I initialize the vector with N elements?
std::vector has a constructor declared as:
vector(size_type N, const T& x = T());
You can use it to construct the std::vector containing N copies of x. The default value for x is a value initialized T (if T is a class type with a default constructor then value initialization is default construction).
It's straightforward to initialize a std::vector data member using this constructor:
struct S {
std::vector<int> x;
S() : x(15) { }
}
class myclass {
std::vector<whatever> elements;
public:
myclass() : elements(N) {}
};
All the constructors that allow you to specify a size also invoke the element's constructor. If efficiency is paramount, you can use the reserve() member function to reserve the size. This does not actually create any elements, so it is more efficient. In most cases, though, supplying the size through the vector constructor is just fine.
Related
I want to have a stack-allocated array initialized by a copy constructor.
I only see methods allocating memory on the heap, or using std::array.
With std::array, it would look like the following:
class A
{
std::array<int, 5> my_array; // I would like to have int my_array[5]; instead of the std::array
int size;
public:
A(const A& p)
: my_array{ p.my_array }, size(p.size) {}
}
How can I implement this without std::array<int,5> but with a plain array (int my_array[5];)? I have added this in the comment in the code.
At the moment, the array contains integers. If this would contain, let's say a class B, which contains also a pointer:
class B
{
int* my_ptr;
}
Does std::array handle this correctly and perform a deep copy?
Arrays cannot be copy-initialised in C++. You can either:
Assign each member in a loop i.e. std::copy in the constructor body.
Or wrap the array inside a class, and use the generated copy constructor. There is a template for such wrapper class in the standard library. It's the std::array that you already know of.
Of course, your class itself is a class that is a wrapper for the array, so you could simply not have user defined copy constructor, and instead use the implicitly generated one:
struct A
{
int my_array[5];
int size;
};
If this would contain, let's say a class B which contains also a pointer ... does the std::array handle this correctly
Yes.
... and performs a deep copy?
No. Copying a std::array copies each element and nothing more. Copying a pointer is a shallow copy.
I want to construct a vector using a non-default constructor of a non-copyable, non-movable class. With the default constructor it works fine, and I can construct a vector, as long as I don't resize it. But somehow with a non-default constructor it seems to have to copy. Does anyone know if I can avoid the copy operation during construction with a non-default constructor so I can keep using vector?
#include <vector>
#include <mutex>
class A {
public:
A(int num) : vec(num) {}
private:
std::vector<std::mutex> vec;
};
class B {
public:
B(int numB, int numA) : vec(numB, numA) {}
private:
std::vector<A> vec;
};
int main() {
B b(2, 3);
return 0;
}
When I try to compile this I get:
/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
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.
I have a member variable two-dimensional vector in a class, like this:
#include <vector>
...
class MyClass {
private:
int vector_size;
std::vector<std::vector<int> > vector_2d;
public:
MyClass(int _vector_size);
~MyClass();
} // class MyClass
I want to know the best way of implementing the constructor MyClass(int _vector_size) to fully initialize the vector to consist of _vector_size empty vectors. The code I have now is as follows (and this works perfectly fine in a little toy program I wrote to test correctness), but I feel like the declaration of temp_vec and the constant temp_vec.clear() might be a little redundant.
MyClass::MyClass(int _vector_size):
vector_size(_vector_size)
{
// initialize vector_2d
vector_2d.clear();
// push initialized 1D vectors
for (int i = 0; i < vector_size; ++i) {
std::vector<int> temp_vec;
temp_vec.clear();
vector_2d.push_back(temp_vec);
}
}
I have also checked other posts such as this, this, and this, but I think my question differs in that I want a vector of specified size that consists of vectors of unspecified size.
std::vector have a constructor overload which takes a size for the vector.
You can use this to initialize your vector:
MyClass::MyClass(int size)
: vector_size(size),
vector_2d(size)
{
}
This will initialize vector_2d to have size elements. Each element is a default-constructed std::vector<int> object (the type of each element).
In your code, vector_2d is default-initialzied as empty std::vector firstly (thus calling of clear() is superfluous), then gets modified in the body of constructor.
You can initialize it directly in member initializer list. E.g.
// initializa vector_2d as containing _vector_size empty std::vector<int>
MyClass::MyClass(int _vector_size):
vector_size(_vector_size), vector_2d(_vector_size) {}
Is it possible in the following example to call the "not default constructor" of class A for every element of mVector within the constructor of class B ?
class A {
public:
A (int n) {/*stuff*/}
};
class B {
public:
B (): mVector(10) {} //call A(int n) constructor?
private:
vector<A> mVector;
};
If you want to set all the elements to the same value, there's a constructor for that
mVector(10, 42) // 10 elements initialised with value 42
If you want to set the elements to different values, use list initialisation
mVector{1,2,3,4,5,6,7,8,9,10} // 10 elements with different values
Strictly speaking, this doesn't do exactly what you describe; it creates a temporary T, and then uses that to copy-initialise each vector element. The effect should be the same, unless your type has weird copy semantics.
You could do one thing here:-
B() : mVector(10, A(10))
{
}
Or
B() : mVector(10, 10)
{
}
Both are essentially the same thing. However, former one is more efficient.
You can use the constructor overload of std::vector taking an element count and a value which for your use case is equivalent to:
std::vector(size_type count, const T& value);
Use it to initialize the elements with the value type's non default constructor:
std::vector<A> mVector(10, A{0}); // 10 elements copy initialized using 'A{0}'.
Or when initializing in the initialization list:
B() : mVector(10, A{0}) {}
The struct
struct Vanish
{
int iCount;
int iRow;
};
I defined a std::vector of Vanish as a member of my class, and want to initialise it in the constructor like this:
class BigClass
{
public:
BigClass();
private:
std::vector<Vanish> tovanish;
};
void BigClass::BigClass()
{
Vanish empty = {0,0};
tovanish.assign(MAX_VANISH, empty);
}
Is there a better way, or is this considered OK?
It is better to do that in the constructor's initializer list:
BigClass::BigClass()
: tovanish(MAX_VANISH)
{
}
That way, you'll avoid possible vector reallocations. Note that you vector's constructor will value-initialize its elements. Value-initialization of the int members in Vanish just zeroes them.
Note that in C++11, using uniform-initialization you could specify other values easily:
BigClass::BigClass()
: tovanish(MAX_VANISH, {42, 24})
{
}
Is there a better way?
Yes, sure,
BigClass::BigClass() : tovanish(MAX_VANISH) {}
This gives you a vector with MAX_VANISH value-initialized Vanish elements.