Why Is the Copy Constructor Called When We Pass an Object as an Argument by Value to a Method

Why is the copy constructor called when we pass an object as an argument by value to a method?

To elaborate the two answers already given a bit:

When you define variables to be "the same as" some other variable, you have basically two possibilities:

ClassA aCopy = someOtherA; //copy
ClassA& aRef = someOtherA; //reference

Instead of non-const lvalue references, there are of course const references and rvalue references. The main thing I want to point out here is, that aCopy is independent of someOtherA, while aRef is practically the same variable as someOtherA, it's just another name (alias) for it.

With function parameters, it's basically the same. When the parameter is a reference, it gets bound to the argument when the function is called, and it's just an alias for that argument. That means, what you do with the parameter, you do with the argument:

void f(int& iRef) {
++iRef;
}

int main() {
int i = 5;
f(i); //i becomes 6, because iRef IS i
}

When the parameter is a value, it is only a copy of the argument, so regardless of what you do to the parameter, the argument remains unchanged.

void f(int iCopy) {
++iCopy;
}

int main() {
int i = 5;
f(i); //i remains 5, because iCopy IS NOT i
}

When you pass by value, the parameter is a new object. It has to be, since it's not the same as the argument, it's independent. Creating a new object that is a copy of the argument, means calling the copy constructor or move constructor, depending on whether the argument is an lvalue or rvalue.
In your case, making the function pass by value is unnecessary, because you only read the argument.

There is a Guideline from GotW #4:

Prefer passing a read-only parameter by const& if you are only going to read from it (not make a copy of it).

Why is the copy constructor called when we return an object from a method by value

The copy constructor is called because you call by value not by reference. Therefore a new object must be instantiated from your current object since all members of the object should have the same value in the returned instance. Because otherwise you would be returning the object it self, which would be returning by reference. In this case modifying the reference object would change the original as well. This is generally not a behavior one wants when returning by value.

Why should the copy constructor accept its parameter by reference in C++?

Because if it's not by reference, it's by value. To do that you make a copy, and to do that you call the copy constructor. But to do that, we need to make a new value, so we call the copy constructor, and so on...

(You would have infinite recursion because "to make a copy, you need to make a copy".)

Is the copy constructor called when an object is passed by reference?

Nope, it won't be called.

A reference is an alias, that is, another name for an already existing variable and not for a copy.

Take a look at this example:

class Line {
public:
int getLength( void ){}
// simple constructor
Line( ){
cout<<"constructor"<<endl;
}
// copy constructor
Line( const Line &obj){
cout<<"copy cts\n";
}
};

void callR(Line& l){
cout<<"call by ref\n";
}
void callC(Line l){
cout<<"call by copy\n";
}

int main() {

Line line;
cout<<"before call by reference\n";
callR(line);
cout<<"before call by copy\n";
callC(line);
}

which produces the following output:

constructor ->  Line line;
before call by reference
call by ref
before call by copy
copy cts
call by copy

As you can see copy constructor is not called when an object is passed by reference. Think of a reference as a pointer.

When object is a argument of function, why does function use copy constructor?

I think inside function, the passed argument is assigned to function parameter

No. The arguments are essentially local variables of the called function, except they are created by the caller before the execution goes into the function. The function does not even know how they were constructed.

why does function use copy constructor?

So this assumption is wrong, the function does not use copy constructor on its arguments. The caller does (if argument is a variable and passed by value, so copy needs to be made).

Why is copy constructor not allowed pass by value?

Passing by value means that the parameter is copied into the function. That calls the copy constructor.

If your copy constructor parameter is pass-by-value... It would call itself... over and over again...

Why is the copy constructor called after the simple constructor is called?

Doesn't Line line(10) only call the Simple constructor

Yes.

Is it because we passed line as an argument to display?

Yes.

So does passing an object as an argument always invoke the copy constructor?

Not necessarily. For example, some types don't have constructors so copying them won't invoke a constructor. Furthermore, if you pass an rvalue, then move constructor may be invoked instead. Or if the type of the argument is different from the type of the parameter, then a converting constructor or conversion operator may be invoked.

If the parameter is a reference (of same type, so no conversion is involved), then no constructor is invoked.

Why copy constructor doesent call itself when an object of arrays is passed as a function argument?

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).

Who calls the copy constructor when passing by value?

obj.foo(passed); will result in the following sequence of steps, generated by a compiler:

  1. Put obj's pointer onto stack frame (the this parameter)
  2. Create a temp variable (this is where the copy constructor is being called)
  3. Put that temp onto stack frame
  4. Make a call to foo()
  5. Once returned from the function - clear up the stack (this is where the destructor is called)


Related Topics



Leave a reply



Submit