push_back () e emplace_back () nos bastidores

Atualmente, estou aprendendo C ++ por conta própria e estou curioso sobre comopush_back() eemplace_back() trabalhar sob o capô. Eu sempre assumi queemplace_back() é mais rápido quando você está tentando construir e empurrar um objeto grande para a parte traseira de um contêiner, como um vetor.

Vamos supor que eu tenho umStudent objeto que eu quero acrescentar na parte de trás de um vetor de Students.

struct Student {
   string name;
   int student_ID;
   double GPA;
   string favorite_food;
   string favorite_prof;
   int hours_slept;
   int birthyear;
   Student(string name_in, int ID_in, double GPA_in, string food_in, 
           string prof_in, int sleep_in, int birthyear_in) :
           /* initialize member variables */ { }
};

Suponha que eu chamepush_back() e empurre umStudent objeto até o final de um vetor:

vector<Student> vec;
vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));

Meu entendimento aqui é quepush_back cria uma instância doStudent objeto fora do vetor e depois o move para a parte de trás do vetor.

Diagrama:

Também posso substituir em vez de push:

vector<Student> vec;
vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);

Meu entendimento aqui é que o objeto Student é construído na parte de trás do vetor, para que nenhum movimento seja necessário.

Diagrama:

Assim, faria sentido que a colocação fosse mais rápida, especialmente se muitos objetos Student fossem adicionados. No entanto, quando cronometrei essas duas versões do código:

for (int i = 0; i < 10000000; ++i) {
    vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));
}

e

for (int i = 0; i < 10000000; ++i) {
    vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);
}

Eu esperava que o último fosse mais rápido, pois o grande objeto Student não precisaria ser movido. Curiosamente, oemplace_back A versão acabou sendo mais lenta (em várias tentativas). Também tentei inserir 10000000 objetos Student, nos quais o construtor recebe referências e argumentos empush_back() eemplace_back() são armazenados em variáveis. Isso também não funcionou, pois o lugar ainda era mais lento.

Verifiquei para ter certeza de que estou inserindo o mesmo número de objetos nos dois casos. A diferença de horário não é muito grande, mas a substituição acabou mais lenta por alguns segundos.

Existe algo errado com meu entendimento de comopush_back() eemplace_back() trabalhos? Muito obrigado pelo seu tempo!

Aqui está o código, conforme solicitado. Estou usando o compilador g ++.

Empurre para trás:

struct Student {
   string name;
   int student_ID;
   double GPA;
   string favorite_food;
   string favorite_prof;
   int hours_slept;
   int birthyear;
   Student(string name_in, int ID_in, double GPA_in, string food_in, 
           string prof_in, int sleep_in, int birthyear_in) :
           name(name_in), student_ID(ID_in), GPA(GPA_in), 
           favorite_food(food_in), favorite_prof(prof_in),
           hours_slept(sleep_in), birthyear(birthyear_in) {}
};

int main() {
    vector<Student> vec;
    vec.reserve(10000000);
    for (int i = 0; i < 10000000; ++i) 
         vec.push_back(Student("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997));
    return 0;
}

Substituir de volta:

struct Student {
   string name;
   int student_ID;
   double GPA;
   string favorite_food;
   string favorite_prof;
   int hours_slept;
   int birthyear;
   Student(string name_in, int ID_in, double GPA_in, string food_in, 
           string prof_in, int sleep_in, int birthyear_in) :
           name(name_in), student_ID(ID_in), GPA(GPA_in), 
           favorite_food(food_in), favorite_prof(prof_in),
           hours_slept(sleep_in), birthyear(birthyear_in) {}
};

int main() {
    vector<Student> vec;
    vec.reserve(10000000);
    for (int i = 0; i < 10000000; ++i) 
         vec.emplace_back("Bob", 123456, 3.89, "pizza", "Smith", 7, 1997);
    return 0;
}

questionAnswers(1)

yourAnswerToTheQuestion