mora mora - 4 years ago 124
C++ Question

Can I set nth value of std::vector by operator[] properly in c++?

I am learning std::vector of c++. I have two trouble with operator[] of std::vector.

Assuming I set the n th value of std::vecotr by operator[],

(1) elements before n th value are not initialized.

(2) I could set the nth value by operator[] but it does not change its size and iterator correctly.

Followings are test code.

/* Test class : its has only id_ and it can print it. */
class Tmp {
public :
Tmp(int new_id) : id_(new_id) {
std::cout << "class Tmp constructor. id = " << id_ << std::endl;
}
void print(void) {
std::cout << "id = " << id_ << std::endl;
}
private :
int id_ = 777;
};

std::vector<Tmp> b;

b.reserve(1);

/* push_back() automatically expands buffer of std::vector. */
b.push_back(Tmp(1));
b.push_back(Tmp(2));
b.push_back(Tmp(3));
b.push_back(Tmp(4));
b.push_back(Tmp(5));

std::cout << "Before operator[] : size = " << b.size() << ", capacity = " << b.capacity() << std::endl;

/* I set the 7 th value. */
b[6] = Tmp(7);
b[6].print();

/* Operator[6] does not change size of std::vector. */
std::cout << "Before operator[] : size = " << b.size() << ", capacity = " << b.capacity() << std::endl;

/* Operator[6] did not expand iterator of std::vector correctly. */
for (auto it = b.begin(); it != b.end(); ++it) {
it->print();
}


Its outputs are following,

class Tmp constructor. id = 1
class Tmp constructor. id = 2
class Tmp constructor. id = 3
class Tmp constructor. id = 4
class Tmp constructor. id = 5
Before operator[] : size = 5, capacity = 8
class Tmp constructor. id = 7
id = 7
After operator[] : size = 5, capacity = 8
id = 1
id = 2
id = 3
id = 4
id = 5


Can I set n th value of std::vector by operator[n]?
If I can do it, How can I initialize values before n th value?

Thank you very much.

Answer Source

Yes, you can set the Nth value with operator[]. However, the element must already exist (pos < size()); unlike some sparse data structures (or std::map), with vector, operator[] will not add elements.

Elements are typically added with push_back, insert, or resize (also assign, emplace, emplace_back...). With resize, there is an optional second argument that specifies the initial value for added elements.

Given your example, you could:

std::vector<Tmp> b;
b.resize(7, Tmp(-1));
b[6] = Tmp(6);

Elements 0-5 would now contain instances of Tmp with _id == -1.

There is also a similar constructor, this code accomplishes the same:

std::vector<Tmp> b(7, Tmp(-1));

std::vector::reserve does not change the size of the container, it only pre-allocates an internal array large enough so that adding elements within that capacity will not require the vector to re-allocate.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download