marco
marco

Reputation: 589

C++ - std::vector initialisation in constructor

In my learning process about C++, I am having hard time understanding the best practice for initializing a vector in this particular setting:

struct Data {
    vector<int> vec;

    Data(const int k) {
        for (int i = 0; i < k; i++) vec.push_back(0);
    }
};

so that in the main function I just declare Data mydata(10); and mydata will have an attribute vector mydata.vec of k=10 elements.

However, I really find unefficient that one has to setup a for loop and fill mydata.vec element by element, so looking online I found other methods that honestly I did not understand. Anyway, I tried to replace that given constructor with

Data(const int k) {
    vec.resize(k);
}

and

Data(const int k) : vec(k,0) {}

with either error messages about modified objects already deleted or segmentation faults happening during runtime. Would you please explain the most C++'ish or most efficient way to initialise a vector in such framework? Consider that for some reason I have little to no understanding about what an initialization list is.

EDIT: Here I propose a minimal example directly taken from my code:

#include <iostream>
#include <vector>

using namespace std;

struct Data {
    vector<unsigned int> mydata, count;

    Data(const unsigned int k) {
        for (unsigned int i = 0; i < 2 * k; i++) {
            mydata.push_back(i + 1);
            //count.push_back(0);  // HERE 1
        }
        count.resize(k); // HERE 2
    }

    void update_stats(const unsigned int p) { count[mydata[0] - 1] += 1; }
};

void twist(Data& stuff, const unsigned int m) {
    unsigned int temp;
    for (unsigned int i = m; i < 2 * m; i++) {
        temp = stuff.mydata[i];
        stuff.mydata.erase(stuff.mydata.begin() + i);
        stuff.mydata.insert(stuff.mydata.begin() + (i - m) * 2, temp);
    }
    stuff.update_stats(m);
}

int main() {
    unsigned int p, k = 200;
    Data stuff(k);

    for (p = 1; p <= k; p++) twist(stuff, p);
    for (p = k; p >= 1; p--) twist(stuff, p);

    cout << stuff.count[stuff.mydata[0] - 1] << endl;
    return 0;
}

I am sorry to not to do better in reducing further. This code produces a segmentation fault. However, commenting the HERE 2 line and using HERE 1 apparently saves the situation. I don't get why.

Upvotes: 0

Views: 733

Answers (1)

Evg
Evg

Reputation: 26282

After the for loop

for (unsigned int i = 0; i < 2 * k; i++)
    count.push_back(0);

the count vector will contain 2k zeros. But after count.resize(k) it will contain only k zeros.


Fixed constructor might look like this:

Data(const unsigned int k) : mydata(2 * k), count(2 * k, 0) {
    std::iota(mydata.begin(), mydata.end(), 1u);
}

To assign sequentially increasing sequence to mydata, you can use std::iota algorithm. , 0 can be dropped without changing the behaviour, but you might want to be explicit about the initial value.

Semantics of these two constructors is very simple:

explicit vector(size_type count);

Constructs the container with count default-inserted instances of T. No copies are made.

vector(size_type count, const T& value);

Constructs the container with count copies of elements with value value.

For T = unsigned int, the "default-inserted instance" is just 0u.

Upvotes: 4

Related Questions