The first form is efficient only if vector.size() is a fast operation. This is true for vectors, but not for lists, for example. Also, what are you planning to do within the body of the loop? If you plan on accessing the elements as in
T elem = some_vector[i];
then you’re making the assumption that the container has
operator(std::size_t) defined. Again, this is true for vector but not for other containers.
The use of iterators bring you closer to container independence. You’re not making assumptions about random-access ability or fast
size() operation, only that the container has iterator capabilities.
You could enhance your code further by using standard algorithms. Depending on what it is you’re trying to achieve, you may elect to use
std::transform() and so on. By using a standard algorithm rather than an explicit loop you’re avoiding re-inventing the wheel. Your code is likely to be more efficient (given the right algorithm is chosen), correct and reusable.
When passing parameters by reference to functions or constructors, be very
careful about const correctness. Pass by non-const reference ONLY if
the function will modify the parameter and it is the intent to change
the caller’s copy of the data, otherwise pass by const reference.
Why is this so important? There is a small clause in the C++ standard
that says that non-const references cannot bind to temporary objects.
A temporary object is an instance of an object that does not have a
variable name. For example:
Stringstream eof problem
cout << "First integer: "; getline(cin, input); sstream.str(input); sstream >> first; // state of sstream may be eof cout << "Second integer: "; getline(cin, input); sstream.str(input); sstream.clear(); // clear eof state sstream >> second; // input from sstream