When I add some tracing output to your `main`,
int main()
{
X xobj1(1), xobj2(2);
vector<X> vec;
cout << "Capacity " << vec.capacity() << " before adding o1\n";
vec.push_back(xobj1);
cout << "Capacity " << vec.capacity() << " before adding o2\n";
vec.push_back(xobj2);
cout << "Capacity " << vec.capacity() << " after adding o2\n";
}
then with both g++ and Visual C++ I get this output:
Capacity 0 before adding o1
Capacity 1 before adding o2
Bye from X with x = 10
Capacity 2 after adding o2
Bye from X with x = 100
Bye from X with x = 20
Bye from X with x = 2
Bye from X with x = 1
Here you can see that that the vector increased its buffer size, by
replacing its buffer, both for the first insertion and for the second
insertion. In the last buffer replacement the copy of the o1 object was
copied a second time, invoking the 10*rhs.x in the copy constructor, a
second time.
I believe the standard doesn't specify the initial capacity of a vector,
and anyway it for sure doesn't specify the capacity after adding an
item, so the behavior here is compiler-specific. You cannot rely on any
particular buffer management strategy except the general complexity
guarantees, which imply a geometric increase of capacity.
You can however guaranteed avoid the buffer replacements during the
insertion sequence by calling `.reserve(a_suitable_initial_capacity)`.
Since this avoids multiple dynamic allocations, which are notoriously
slow, it's often done as a matter of course. I guess if `std::vector`
were designed today, with what we now know of usage patterns, it would
have had constructors that supported specification of an initial
capacity, and it might possibly have provided access to uninitialized
parts of the buffer for POD item type, for use as API function result.
Cheers & hth.,
- Alf