#include<iostream>
#include<vector>
#include<list>
#include<queue>
#include<map>
using namespace std;
class dog{
public:
string name;
dog();
dog(const dog & d);
void barkname(){
cout<<"bark "<<name<<endl;
}
virtual ~dog(){
//cout<<"delete dog "<<name<<endl;
}
};
dog::dog(){
cout<<"blank dog"<<endl;
this->name="blank";
}
dog::dog(const dog &d){
cout<<"copy dog"<< " "+d.name<<endl;
string temp=d.name;
this->name=temp+" copied";
}int main(){
dog d;
d.name="d";
dog dd;
dd.name="dd";
dog ddd;
ddd.name="ddd";
vector<dog> doglist;
doglist.push_back(d);
doglist.push_back(dd);
doglist.push_back(ddd);
return 0;
}
Здравствуйте, я новичок в cpp. Я пытался использовать конструктор копирования в моей классной собаке. Я толкнул трех собак в вектор, используя push_back три раза. Поэтому я ожидал, что конструктор копирования будет вызван три раза. Однако после выполнения кода я обнаружил, что конструктор копирования вызывался шесть раз со следующими результатами:
blank dog
blank dog
blank dog
copy dog d
copy dog dd
copy dog d copied
copy dog ddd
copy dog d copied copied
copy dog dd copied
Я совершенно не понимаю, почему собаку копируют так много раз. Я только извиняюсь за push_back три раза.
Спасибо.
Спасибо за указание на аналогичный вопрос:
почему конструктор копирования вызывается дважды при выполнении vector.push_back
В этом посте автор только push_back один объект, но конструктор копирования был вызван дважды. Однако, в моем случае, когда я вызываю push_back один раз, конструктор копирования вызывается только один раз. Я понял, где моя проблема, спасибо всем за вашу помощь.
Вектору нужно место для размещения ваших собак, поэтому он выделяет им память. Но он не может выделить бесконечную память. Когда вы добавляете больше собак, вектор должен выделять больший блок памяти, и каждый раз, когда он это делает, он должен перемещать ваших собак в их новый дом. Единственный способ сделать это с вашим классом в его нынешнем виде — это скопировать их, а затем перевести оригиналы в спящий режим.
Если бы вы зарезервировали достаточно места для всех собак в первую очередь (как показано ниже), то в этом не было бы необходимости, и ваши собаки могли бы заняться делом правильной неприятности, без отвлечения внимания постоянно движущегося дома.
doglist.reserve(3);
Вывод будет более понятным, если добавить операторы, отображающие емкость вектора. Например
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class dog{
public:
string name;
dog();
dog(const dog & d);
void barkname(){
cout<<"bark "<<name<<endl;
}
virtual ~dog(){
//cout<<"delete dog "<<name<<endl;
}
};
dog::dog(){
cout<<"blank dog"<<endl;
this->name="blank";
}
dog::dog(const dog &d){
cout<<"copy dog"<< " "+d.name<<endl;
string temp=d.name;
this->name=temp+" copied";
}int main()
{
dog d;
d.name="d";
dog dd;
dd.name="dd";
dog ddd;
ddd.name="ddd";
vector<dog> doglist;
cout << "\nInitial capacity: " << doglist.capacity() << endl;
doglist.push_back(d);
cout << "After adding the first dog capacity: " << doglist.capacity() << endl;
doglist.push_back(dd);
cout << "After adding the second dog capacity: " << doglist.capacity() << endl;
doglist.push_back(ddd);
cout << "After adding the second dog capacity: " << doglist.capacity() << endl;
return 0;
}
Выход программы
blank dog
blank dog
blank dog
Initial capacity: 0
copy dog d
After adding the first dog capacity: 1
copy dog dd
copy dog d copied
After adding the second dog capacity: 2
copy dog ddd
copy dog d copied copied
copy dog dd copied
After adding the second dog capacity: 4
Вывод может отличаться в зависимости от реализации вектора.
Рассматривая вывод, вы можете видеть, что изначально вектор не выделяет память для потенциально добавленных элементов. Его емкость равна 0.
Когда первый элемент добавлен, вектор выделяет память для этого одного элемента и копирует предоставленный объект в эту память.
Когда добавляется второй элемент, вектор выделяет новый экстент памяти и копирует новый элемент и первый элемент из текущего экстента памяти в новый экстент памяти и так далее.
Можно сказать, что вектор изначально зарезервирует память для трех элементов.
Например
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class dog{
public:
string name;
dog();
dog(const dog & d);
void barkname(){
cout<<"bark "<<name<<endl;
}
virtual ~dog(){
//cout<<"delete dog "<<name<<endl;
}
};
dog::dog(){
cout<<"blank dog"<<endl;
this->name="blank";
}
dog::dog(const dog &d){
cout<<"copy dog"<< " "+d.name<<endl;
string temp=d.name;
this->name=temp+" copied";
}int main()
{
dog d;
d.name="d";
dog dd;
dd.name="dd";
dog ddd;
ddd.name="ddd";
vector<dog> doglist;
doglist.reserve( 3 );
//^^^^^^^^^^^^^^^^^^^
cout << "\nInitial capacity: " << doglist.capacity() << endl;
doglist.push_back(d);
cout << "After adding the first dog capacity: " << doglist.capacity() << endl;
doglist.push_back(dd);
cout << "After adding the second dog capacity: " << doglist.capacity() << endl;
doglist.push_back(ddd);
cout << "After adding the second dog capacity: " << doglist.capacity() << endl;
return 0;
}
В этом случае вывод будет выглядеть
blank dog
blank dog
blank dog
Initial capacity: 3
copy dog d
After adding the first dog capacity: 3
copy dog dd
After adding the second dog capacity: 3
copy dog ddd
After adding the second dog capacity: 3
Таким образом, в этом случае вектор копирует только недавно добавленный элемент в предварительно выделенном объеме памяти.