Why is the move constructor only called when there is already an element in the vector?

I am trying to learn new features in C ++ 11. And I am testing the following code in XCode.

#include <iostream>
#include <string>
#include <vector>

class CClass
{
    std::string s;
public:
    CClass()
    {
        std::cout<<"Default Constructor"<<std::endl;
    }
    CClass(const std::string v) :s(v) {
        std::cout<<"Constructor"<<std::endl;
    }

    CClass(const CClass& other): s(other.s) {
        std::cout<<"Copy Constructor"<<std::endl;
    }
    CClass(CClass&& a) noexcept
    {
        std::cout<<"Move Constructor"<<std::endl;
        s = std::move(a.s);
    }
    CClass& operator = (const CClass& other)noexcept
    {
        std::cout<<"Copy Assignment"<<std::endl;
        if(this != &other)
        {
            s = other.s;
        }
        return *this;
    }
    CClass& operator = (CClass&& other) noexcept
    {
        std::cout<<"Move Assignment"<<std::endl;
        if(this != &other)
        {
            s = std::move(other.s);
        }
        return *this;
    }
};

int main()
{
    std::vector<CClass> v;
    CClass x("hello");
    //v.push_back(x);
    std::cout<<"--------------------"<<std::endl;
    v.emplace_back("uiuiu");
    std::cout<<"--------------------"<<std::endl;
}

      

When I uncomment the push, I get the following output:

Constructor
Copy Constructor
--------------------
Constructor
Move Constructor
--------------------

      

Otherwise, if I comment this out, I get:

Constructor
--------------------
Constructor
--------------------

      

My question is, why is the move constructor not being called in the second case? It is called only in the first case, when the vector is not initially empty.

+3


source to share


1 answer


This is because one element in the vector needs to be moved to a new memory location. The reason for this is that the new size will exceed the vector capacity, so new memory with new capacity had to be allocated for the vector.

From std::vector::emplace_back

:

If new is size()

greater than capacity()

, then all iterators and references (including the past-end iterator) become invalid. Otherwise, only the last end iterator is invalid.



Iterators and references are invalid for the same reason: because the elements are now stored in a new location in memory.

If you call reserve

in the first case, you will see that the move constructor is not being called:

CClass x{"hello"}; // constructor
v.reserve(2); // make space for 2 elements (you could have also used resize)
v.push_back(x); // copy constructor
v.emplace_back("uiuiu"); // constructor

      

+7


source







All Articles