0

Simple program that doesn't do anything much, but can anyone explain why copy constructor is not calling itself when an array of objects is passed in function argument? Works perfectly fine when only one object is initialized

class Student{
    public:
        Student(string name_val="empty",int tg=2019,int gu=0):
            name{name_val},current_year{tg}{cout<<"Constructor is called "<<endl;}
        Student(const Student &source):
            name{source.name},current_year{source.current_year}{
            cout<<"Copy constructor  is called "<<endl;
            }
        ~Student(){cout<<"Destructor is called "<<endl;}

        void set(){
            cout<<"Input name and surname: ";getline(cin,name);
        }   
    private:
        string name;
        int current_year;
};

void input(Student s[],int n){//Should display when input function is called
    for(int i=0;i<n;i++){
        cout<<"Input data for "<<i+1<<". student\n";
        s[i].set();
    }
}

int main(){
    Student S[2];//Calls constructor
    input(S,2);//Should call copy constructor 
    return 0;
}
Stack Danny
  • 7,754
  • 2
  • 26
  • 55
Finixzz
  • 19
  • 8

1 Answers1

0

It's only passing a pointer to S, so it's not copying any Student. If you want to actually pass a copy of the array instead of just a pointer to it (and thus leave the original unchanged), you can wrap it using std::array like this:

void input(std::array<Student, 2> s)

And in main:

std::array<Student, 2> S;//Calls constructor

This way you get:

Constructor is called
Constructor is called
Copy constructor  is called
Copy constructor  is called

However, the array will always have to be of the same size this way, unlike in your solution where you pass the size as an extra parameter. You could solve this issue with templates by declaring the function like this:

template <unsigned int n>
void input(std::array<Student, n> s) {

And calling it like this:

input<2>(S);

Or, if you don't mind slightly lower performance, just use std::vector instead:

void input(std::vector<Student> s) {
    for (int i = 0; i < s.size(); i++) {
        cout << "Input data for " << i + 1 << ". student\n";
        s[i].set();
    }
}

int main() {
    std::vector<Student> S(2);//Calls constructor
    input(S);//Should call copy constructor 
    return 0;
}

However, those don't do the same thing as your original function anymore, because since you're now passing just a copy, the original isn't modified. If you pass a reference however:

void input(std::vector<Student> &s) {

The original is modified and you don't see Copy constructor is called anymore (this also works with the std::array version).

Blaze
  • 16,736
  • 2
  • 25
  • 44
  • The last snippet is missing the `&`. `std::array` is an option only if your argument is really of fixed size. When it's not, templating doesn't help. `std::vector` seems to be what OP is looking for. – Frax May 22 '19 at 14:09
  • @Frax thanks for pointing out the error. You're right, `std::vector` definitely is the way to go, I edited the post to mention that. – Blaze May 22 '19 at 14:12
  • @Blaze thanks ! Finally I think got the point, practically I could make a function set name that would make copy of one object, and then make another function with an array of objects. That way throughout the for loop, each object would get its own copy. Am I right ? – Finixzz May 22 '19 at 18:36
  • @Finixzz if I understand this correctly, you want to pass a pointer to an array to the function, which then calls a setter on the objects in the array? Sure, that'll work. – Blaze May 23 '19 at 06:10