'Vector of objects without a default constructor and iterator

I am learning to use C++ vectors, and I can't quite understand the output of the following program:

#include <iostream>
#include <vector>

using namespace std;

class Custom {
public:
    int v;

    Custom() = delete;

    explicit Custom(int v) : v{v} {};

    Custom(const Custom &) : v{4} {

    }

    friend ostream &operator<<(ostream &os, const Custom &th) {
        os << "V is " << th.v << endl;
        return os;
    }
};


int main(int argc, char *argv[]) {
    vector<Custom> c(2, Custom(3));
    c[0].v = 5;

    for (auto i: c) {
        cout << i << endl;
    }

}

I expected it to produce the output

V is 5
V is 4

But instead it produces

V is 4

V is 4

Am I missing something obvious? Thanks.



Solution 1:[1]

This range based loop is making copies:

for (auto i: c) {
    cout << i << endl;
}

And the copy constructor initializes v to 4 (and does not make a copy):

Custom(const Custom &) : v{4} {

}

You can either implement a proper copy constructor or use references in the loop to get the desired output:

for (const auto& i: c) {
    cout << i << endl;
}

I would suggest to do both, because this copy constructor is not doing a copy by any means. The compiler generated copy constructor should be fine:

Custom(const Custom &) = default;

PS: The fact that Custom has a deleted default constructor is not really relevant for the posted code. Nowhere in the code a Custom is default constructed. Also there is no iterator in your code. In the range based loop i is a copy/reference of the elements in the vector, it is not an iterator.

Solution 2:[2]

When you wrote:

for (auto i: c) //this uses copy constructor to copy initialize each element one by one from the vector
{

}

In the above snippet, each individual element of the vector is used to copy initiaize a temporary object named i while iterating through the vector. And since you have the v{4} in the constructor initializer list of the copy constructor you get the mentioned output.

To solve this you should replace: auto i: c with auto &i: c or const auto &i: c as shown below:

for (const auto &i: c) 
{
   cout << i << endl;
}

Now the elements of the vector are not copied into i. Instead they are references to the object themselves and so you'll get your expected output.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Anoop Rana