I am trying to create a vector of objects and would like the not default constructor to be called uniquely for each object in the vector. I have an simplified example below.
In my example I have an object with two constructors, default (no args) and non-default (1 arg). When I initialized a vector of size 10 using the default constructor (v1), the constructor gets called 10 times (as can be seen by the random numbers). However, when I try to initialize a vector with the objects non-default constructor (v2), the object constructor is called once and this object is copied to the remaining elements in the vector (x is no longer many different random numbers).
Is it possible to initialize a vector of N objects so that each objects non-default constructor is called for each object?
Example Code:
#include <vector>
#include <iostream>
#include <cstdlib>
struct Obj {
int x;
Obj() {
x = rand() % 5;
}
Obj(int max_x) {
x = rand() % max_x;
}
};
int main() {
std::vector<Obj> v1(10); // Default constructor
std::vector<Obj> v2(10, 5); // Non-Default Constructor
for(int i=0; i<10; ++i) {
std::cout << v1[i].x << ", " << v2[i].x << std::endl;
}
}
Output:
3, 2
1, 2
2, 2
0, 2
3, 2
0, 2
1, 2
2, 2
4, 2
1, 2
Solution
The following function can be used to return an object vector where the not default constructor is called of each object.
template <typename T, typename ... Args> std::vector<T> InitVector(const int n, Args ... args) {
std::vector<T> vec;
for(int i = 0; i < n; ++i) {
vec.emplace_back(args ...);
}
return vec;
}
Here're two workarounds.
Use list initialization.
std::vector<Obj> v2{5, 5, 5, ...};
Use emplace_back
to insert the elements later.
std::vector<Obj> v2;
v2.reserve(10);
for (int i=0; i<10; ++i) {
v2.emplace_back(5);
}
I'm not quite sure whether this could be a solution but you could overload the copy constructor to do the intended construction.
I tried the idea with overloading the copy constructor:
#include <vector>
#include <iostream>
#include <cstdlib>
struct Obj {
const int max_x;
int x;
Obj(): Obj(5) { }
Obj(int max_x): max_x(max_x), x(rand() % max_x) { }
Obj(const Obj &obj): Obj(obj.max_x) { }
};
int main() {
std::vector<Obj> v1(10); // Default constructor
std::vector<Obj> v2(10, 5); // Non-Default Constructor
for(int i=0; i<10; ++i) {
std::cout << v1[i].x << ", " << v2[i].x << std::endl;
}
}
Output:
3, 2
1, 0
2, 4
0, 3
3, 1
0, 0
1, 1
2, 2
4, 1
1, 1
Live Demo on coliru
It's better but the draw back is the additional member in struct Obj
. :-(
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