2016-07-03 3 views
4
#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 три раза. Поэтому я ожидал, что конструктор копирования будет вызываться три раза. Тем не менее, после выполнения кода, я обнаружил, что конструктор копирования был вызван в шесть раз, со следующими результатами:Когда конструктор копирования вызывается в cpp?

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. Спасибо.

Спасибо за указание на аналогичный вопрос: why the copy-constructor is called twice when doing a vector.push_back

В этой статье автор только push_back один объект, но конструктор копирования был вызван дважды. Однако, в моем случае, когда я вызываю push_back один раз, конструктор копирования вызван только один раз. Я понял, где моя проблема, спасибо всем за вашу помощь.

+0

Возможный дубликат [почему конструктор copy вызывается дважды при выполнении vector.push \ _back] (http://stackoverflow.com/questions/30358475/why-the-copy-constructor-is-called-twice -when-doing-a-vector-push-back) – Cristy

+0

@Cristy: Не совсем, нет. –

+0

@LightnessRacesinOrbit Как складываются вопросы? : D – Cristy

ответ

17

Вектор нуждается в некотором месте для размещения ваших собак, поэтому он выделяет для них память. Но он не может выделить бесконечную память. Когда вы добавляете больше собак, вектор должен выделять больший блок памяти, и каждый раз, когда он делает это, он должен переместить ваших собак в их новый дом. Единственный способ сделать это, с вашим классом, как он сейчас разрабатывается, - скопировать их, а затем положить оригиналы в режим сна.

Если вы зарезервировали достаточное пространство для всех собак в первую очередь (как показано ниже), то это не было бы необходимо, и ваши собаки могли бы справиться с тем, что работали над тем, чтобы быть подходящей неприятностью , без отвлечения постоянно движущегося дома.

doglist.reserve(3); 
+4

Lol: «он должен переместить ваших собак в их новый дом» :) – Cristy

+1

И он перераспределяет каждый раз? Я слышал, что векторы предварительно выделяют несколько записей. Также не могут ли они использовать конструкторы перемещения, если они существуют? (они не в этом случае, я просто спрашиваю) –

+3

@PaulStelian: Не каждый раз - [темпы роста отличаются, но, как правило, геометрические] (http://stackoverflow.com/q/5404489/560648). И да элементы будут перемещены, где это возможно. –

1

Выход будет более понятным, если добавить утверждения, отображающие емкость вектора. Например

#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 

Так что в этом случае только векторные копии вновь добавленный пункт в предварительно выделенной степени памяти.

Смежные вопросы