Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

when does a copy constructor get called in cpp?

#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;
}

Hello, I'm new to cpp. I tried to use copy constructor in my class dog. I pushed three dogs into the vector, using push_back three times. So I expected copy constructor to be called three times. However, after executing the code, I found that copy constructor was called six times, with the following results:

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

I'm quite confused about why the dog is copied so many times. I only excute push_back for three times. Thank you.

Thank you for pointing out a similar question: why the copy-constructor is called twice when doing a vector.push_back

In this post, the author only push_back one object, but copy constructor got called twice. However, In my case, when I call push_back once, copy constructor got called only once. I have understood where my problem is, thank you all for your help.

like image 210
Casualet Avatar asked Dec 01 '22 12:12

Casualet


2 Answers

The vector needs some place to put your dogs, so it allocates memory for them. But it cannot allocate infinite memory. As you add more dogs, the vector needs to allocate a bigger block of memory, and every time it does that it must relocate your dogs to their new home. The only way to do that, with your class as it is currently designed, is to copy them, then put the originals to sleep.

If you'd reserved enough space for all the dogs in the first place (as shown below), then this wouldn't have been necessary and your dogs could have gotten on with the business of running about being a right nuisance, without the distraction of constantly moving house.

doglist.reserve(3);
like image 59
Lightness Races in Orbit Avatar answered Dec 05 '22 07:12

Lightness Races in Orbit


The output will be more clear if to add statements that display the capacity of the vector. For example

#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;
}

The program output is

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

The output can differ depending on the vector implementation.

Considering the output you can see that initially the vector does not allocate memory for potentially added elements. Its capacity is equal to 0.

When the first item is added the vector allocates memory for this one item and copies the supplied object in this memory.

When the second item is added then the vector allocates a new extent of memory and copies the new element and the first one from the current memory extent to the new memory extent and so on.

You could say the vector that it would initially reserve memory for three items.

For example

#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;
}

In this case the output will look like

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

So in this case the vector copies only the newly added item in the pre-allocated memory extent.

like image 40
Vlad from Moscow Avatar answered Dec 05 '22 08:12

Vlad from Moscow