0
class test
{
    char *str;
    public:
        test(char *p_str) /**default constructor**/
        {
            cout<<"Default\n";
            int l = strlen(p_str) + 1;
            str = (l ? new char[l] : 0);
            memcpy(str,p_str,l);
        }
        test(const test& ob) /**copy**/
        {
            cout<<"Copy\n";
            int l = strlen(ob.str) + 1;
            str = (l ? new char[l] : 0);
            memcpy(str,ob.str,l);
        }
        test(test&& ob) /**move constructor **/
        {
            cout<<"Move Constructor\n";
            str = ob.str;
            ob.str = nullptr;
        }
        void my_swap(test &ob1 , test &ob2) /**swap function**/
        {
            swap(ob1.str , ob2.str);
        }
        test& operator=(test ob) /**copy is called because of pass by value **/
        {
            cout<<"Copy Assignment operator\n";
            my_swap(*this,ob);
            return *this;
            /**copy is destroyed as object passed by value is destroyed just after the function returns;**/
        }
        ~test()
        {
            cout<<"Destructor\n";
            delete[] str;
        }
        void print_str()
        {
            cout<<str<<"\n";
        }

};

The above class contains simple implementation of rule of 5 in c++.Now when a vector of this class is created as following.

int main()
{
    vector<test> vec1;
    vec1.push_back(test("Hi!There"));
    return 0;
}

I get the following output

Default

Move Constructor

Destructor

Destructor

And when one more object is pushed into the vector like this

int main()
{
    vector<test> vec1;
    vec1.push_back(test("Hi!There"));
    vec1.push_back(test("Hello! There"));
    return 0;
}

The output is

Default

Move Constructor

Destructor

Default

Move Constructor

Copy

Destructor

Destructor

Destructor

Destructor

Now my question is why is the copy constructor called in the second case and not the first.

Thanku

1 Answers1

1

Since you have 5 destructor calls instead of 4 I assume that the vector had to reallocate it's internal storage when you tried to push the second item. This means that the vector had to move the first pushed item to the newly allocated (larger) memory area. However when a vector reallocates it storage and has to transfer items from the old memory block the the new one, it may happen that the item is transferred with copy instead of move. Reason: How to enforce move semantics when a vector grows?

In your case the correct solution would be using vec1.reserve(2) (before pushing items) to avoid the unnecessary reallocation even if the reallocation happens with move. Frequent reallocation is often the target of memory usage optimization.

Community
  • 1
  • 1
pasztorpisti
  • 3,760
  • 1
  • 16
  • 26