I know in c 11 I can use initializer to create array/vector elements one by one like:
int ar[10]={1,2,3,4,5,6};
vector<int> vi = {1,2,3,4};
This is done manually, but what if I wish to initialize an array/vector with 10000 elements and specify their value, can it be done in one statement, RAII pattern?
E.g. I've defined a class:
class Somebody{
int age;
string name;
public:
Somebody():age(20),name("dummy"){} // default ctor
Somebody(int a, const char* n):age(a),name(n){} // but I wish to call this ctor
Somebody& operator = (const Somebody& s) {...}
};
Then in main function:
int main(int argc, char const *argv[])
{
Somebody obj(2, "John"); // parameterized ctor
Somebody ar[300]; // initialized, but called default ctor
for(int i=0;i<300; i){ // initialize again in a loop
ar[i] = ... ; // call operator =
...
Question: could Somebody ar[300]
be constructed with parameterized ctor?
If not, then I have to create this object array ar
first(Compiler generated code will loop and call default parameter), then apply value changes for each object. This seems quite a bit redundant of cpu cycles.
Is there a way to do what I expected with just one call? (Loop and update each array element with parameterized ctor)
Thanks.
CodePudding user response:
Well, with simple arrays there's always the direct approach:
Somebody ar[300]={ {1, "Larry"}, {2, "Moe"}, {3, "Curly"} ... };
You'd have to write out whatever you want to write out 297 more times. This gets real old, real quickly.
One could potentially concoct, in a pinch, something that involves a variadic template to generate the whole bunch of them. Something like that is the classical approach to generating a fast 256-value array lookup for a textbook-style base64 decoder.
But for the simplistic case where you only want the same value, just #n
copies of it, the simplest solution is to use a std::vector
instead of a plain array and use one of its contructors that takes a single object and the vector size, and then constructs the vector by copying the object the requisite number of times. That involves slightly more overhead but is generally good enough, for this simple use case.
CodePudding user response:
You can use std::fill_n:
Somebody obj(2, "John");
Somebody ar[300];
fill_n(ar, 300, obj);
CodePudding user response:
You can not do this with C-style arrays. One of the many reasons you should not be using them in the first place.
You should be using std::vector
, which provides a constructor to populate the vector using a single value:
std::vector<Somebody> ar{300, Somebody("42", "filler")};
But often it is better to not create such dummy entries in the first place. A std::vector
can grow dynamically so you can just add Somebody
objects to it as you get their age and name.
std::vector people; people.reserve(2); // optional but makes adding lots of objects more efficient Somebody adam(42, "Adam"); people.push_back(adam); people.emplace_back(23, "Eve");
This shows you 2 ways to add objects to the vector, the push_back
adds objects to the vector (copies/moves it) while emplace_back
will construct the object directly in the vector, which is often more efficient.
If you want a fixed size array then you can use
std::array<Somebody, 300> ar;
ar.fill(Somebody(23, "filler"));
But this has the same problem as the C-style array of using the default construtor. std::arrays::fill
replaces all the objects with a new value.
Unfortunately there is no array constructor to do this in one go which is rather unfortunate.