Home > Enterprise >  Why is the move constructor called 2 times?
Why is the move constructor called 2 times?

Time:11-22

main.cpp

#include <iostream>
#include <vector> 
#include "Person.h"
using namespace std;

int main()
{
    vector<Person> test{};

    test.push_back (Person{ "Chinese", 16 });
    test.push_back(Person{});

    return 0;
}

Person.h

#pragma once
#include <iostream>

class Person
{
public:
    std::string* ethnicity;
    int age;
       
    Person(std::string ethnicity = "Caucasian", int age = 15);
    ~Person();
    Person(const Person& source);
    Person (Person&& source) noexcept;
};

Person.cpp

#include "Person.h"

Person::Person(std::string ethnicity, int age)
    : age(age)
{
    this->ethnicity = new std::string; 
    *this->ethnicity = ethnicity;
}

Person::Person(const Person& source)
    : Person(*source.ethnicity, source.age)
{
    std::cout << "Copy constructor deep called!" << std::endl;
}

Person::Person(Person&& source) noexcept
    : ethnicity(source.ethnicity), age(source.age) 
{
    std::cout << "Move constructor called!" << std::endl; 
    source.ethnicity = nullptr;
}

Person::~Person()
{
    if (this->ethnicity != nullptr)
        std::cout << "Destructor called!" << std::endl;
    else
        std::cout << "Destructor called for nullptr!" << std::endl;
    delete ethnicity;
}

Output

image

From my understanding, only 2 move constructors should be called. But why are 3 move constructors called? The first push_back() should create a temporary object through the constructor, and then the move constructor will be called, then the destructor would be called for the temporary object. The process would be the same for the 2nd push_back(), so in total there would only be 2 move constructors getting called. But why are there 3?

CodePudding user response:

But why are there 3?

When std::vector needs more space, it allocates a new array and copies/moves all the existing elements from the old array to the new array.

Solution 1
To minimize this, use the std::vector::reserve() member function before pushing elements onto the vector. This pre-allocates the needed space.

vector<Person> test;
test.reserve(2);
test.push_back(Person{"Chinese", 16});
test.push_back(Person{});

Solution 2
Or you can create the vector to be of a particular size, like:

vector<Person> test(2);
test.at(0) = Person{"Chinese", 16};
test.at(1) = Person{};

Note that in solution 2, we first create a vector of size 2. Now since the std::vector is already of size 2, we do not use push_back because this will mean we add more elements to the vector and the vector size will increase and become 4(if we use push_back 2 times) which is not what we want. What we want now is to set the 0th and 1st index element. Just make sure you handle(or add the assignment operator= if not already) assignment correctly in solution 2.

  •  Tags:  
  • c
  • Related