Onkar N Mahajan
Onkar N Mahajan

Reputation: 437

Correct usage of vector<int>::size_type

I saw in some very well known books on C++ that --

vector<int> ivec;

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec.push_back(i);
    ivec.push_back(i);  // duplicate copies of each number

}

I was wondering why vector<int>::size_type is used here. They are not comparing i with size of the vector. Intent is to insert 10 int's in the vector, so int i = 0 would be a right thing to do, isn't it ?

vector<int>::size_type would be typedef for std::size_t which in turn will be unsinged int, but here we are storing int's in the vector.

Please clarify my understanding about vector<int>::size_type. Is it fair to use it in the for loop above ?

Upvotes: 2

Views: 2009

Answers (4)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385194

In general

Yes, your value type is int.

But that's not what size_type is talking about. size_type is the type of the indices of the vector. It's the type of the size of the vector (hence its name!).

We use a type alias for this (provided by the standard library) because it may/will differ across systems. It'll often be a size_t, which itself is a standard alias for some big unsigned type, albeit which one you cannot predict in general for a portable program.


But…!

This particular example is doubly confusing, because the book author really is populating vector values using the size type. This is not necessarily "wrong": in the range 0-9, it's not going to break. The compiler will just implicitly convert the integers in the usual way.

But it is expressing intent incorrectly.

I imagine it used to look like this:

vector<int> v(5);
for (vector<int>::size_type i = 0; i < v.size(); i++)
   v[i] = 42;

Then somebody has changed the loop body (such that i now is used for values, rather than for indices) and not thought about changing the loop preamble.

Making i an int would be far more clear and obvious.

Overall I'd consider avoiding these "well-known books" or, at least, checking their errata to see whether the code has been adjusted post-publication, because that's quite a strange example of C++.

Upvotes: 0

Evg
Evg

Reputation: 26302

To avoid implicit casts and compiler warnings you can be explicit about what you push_back:

vector<int> ivec;

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec.push_back(static_cast<int>(i));
    ivec.push_back(static_cast<int>(i));
}

Using size_type and static_cast in this code seems to be artificial. It would be more meaningful in the following example (a combination of @AlanBirtles's examples):

vector<int> ivec(20);

for (vector<int>::size_type i = 0; i != 10; ++i) {
    ivec[2 * i] = ivec[2 * i + 1] = static_cast<int>(i);
}

Upvotes: 0

Alan Birtles
Alan Birtles

Reputation: 36399

I'd say no, this code is not correct and many compilers will warn about the implicit cast from size_t to int.

vector::size_type/size_t should always be used for vector indexes but if you have a vector of int then you should be inserting ints into it.

The correct code would be:

vector<int> ivec;

for (vector<int>::value_type i = 0; i != 10; ++i) {
    ivec.push_back(i);
    ivec.push_back(i);  // duplicate copies of each number
}

for (vector<int>::size_type i = 0; i < ivec.size(); ++i) {
    std::cout << ivec[i] << "\n";
}

Upvotes: 4

RealPawPaw
RealPawPaw

Reputation: 986

Basically, the above code is 'fine' in the sense that it compiles and does the intended job, as others have said.

When they said the intent was to insert ten ints in the vector, the ints are guaranteed positive because of how the loop is formatted, so the unsigned int will just convert into int.

However, I don't believe this is good practice as you said - the size type has nothing to do with the type of the elements being inserted - the size type is basically always an unsigned int. Just using int or value_type would obviously make the intent of the code clearer.

Upvotes: 5

Related Questions