Why use references to the parameters of the copy constructor?
I found a lot of information saying that it is to avoid unlimited calls, but I still can't understand it.
When you pass to a method by value, a copy is made of the argument. Copying uses the copy constructor, so you get a chicken and egg situation with infinite recursive calls to the copy constructor.
Response to comment:
Passing by reference does not make a copy of the object begin passed. It simply passes the address of the object (hidden behind the reference syntax) so the object inside the copy constructor (or any method to which an object is passed by reference) is the same object as the one outside.
As well as solving the chicken-and-egg here, passing by reference is usually (for larger objects - larger than the size of a point) faster.
Response to further comment:
You could write a kind of copy constructor that passed by pointer, and it would work in the same way as passing by reference. But it would be fiddly to call explicitly and impossible to call implicitly.
Declaration:
class X
{
public:
X();
X(const X* const pOther);
};
The explicit copy:
X x1;
X x2(&x1); // Have to take address
The implicit copy:
void foo (X copyOfX); // Pass by value, copy made
...
X x1;
foo (x1); // Copy constructor called implicitly if correctly declared
// But not matched if declared with pointer
foo (&x1); // Copy construcxtor with pointer might (?) be matched
// But function call to foo isn't
Ultimately, such a thing would not be regarded as a C++ copy constructor.
This code:
class MyClass {
public:
MyClass();
MyClass(MyClass c);
};
does not compile. That is, because the second line here:
MyClass a;
MyClass b(a);
should theoretically cause the infinite loop you're talking about - it should construct a copy of a to before calling the constructor for b. However, if the copy constructor looks like this:
MyClass(const MyClass& c);
Then no copies are required to be made before calling the copy constructor.
From this webpage
A copy constructor is called when an object is passed by value. Copy
constructor itself is a function. So if we pass an argument by value
in a copy constructor, a call to copy constructor would be made to
call copy constructor which becomes a non-terminating chain of calls.
Therefore compiler doesn’t allow parameters to be passed by value.
By passing the argument by value the copy constructor calls itself, entering in an infinite 'recursion cycle'. The link above explain pretty well the basic topics about the copy constructor.
Related
Why do we pass object of a class by reference. When I remove ampersand (&) I get following error.
"Copy constructor of class A may not have parameter of type A"
What does this mean? may be compiler is not considering given a copy constructor and using default one.If this is that case why default one is being called. In short why we use ampersand and what will happen? if we don't.
class A
{
public:
A()
{
}
A(A& tmp)
{
id = 2*tmp.id;
}
public:
int id;
};
int main()
{
A obj;
obj.id = 10;
A obj1(obj);
cout << obj1.id;
}
In C++, functions can take their parameters by value or by reference. If they take their parameters by value, that value must be copyable. If a copy constructor could take its parameter by value, then you would need a copy constructor to pass it its parameter, which would cause an endless loop.
Consider:
class MyInt
{
int m;
public:
MyInt(int i)
{
m = i;
}
MyInt(MyInt j)
{
j.m++;
m = j.m;
}
};
MyInt a(1);
MyInt b(a);
How can the compiler make this work? If it uses the default copy constructor, then why would it ever need to call my constructor? And if it uses my constructor, how does it prevent a.m from being incremented (which is clearly wrong, a should not be changed when it is passed by value) given that there's no code to give the constructor its own copy?
Imagine what would happen if you don't:
1) The parameter is now passed by value to the copy constructor
2) In order to pass it by value it invokes the copy constructor
3) Goto 1
There are three ways to pass variables into functions/methods in C++: Pass by value, pass by address, and pass by reference (which is actually pass by address in a pretty wrapper). Pass by address and pass by reference are the simplest in that what gets passed into the underlying function/method is actually the memory address of where the object your passing lies. In order to pass by value, though, a copy of the source object must be made. That's the job of the copy constructor.
In order for the copy constructor to accept an instance of A, you must be able to make a copy of A, which requires a copy constructor, a recursive requirement.
It's the copy constructor that's called when you pass an object by value.
So if your copy constructor requires the instance to be copied before it can run, how can it ever run?
The ampersand tells it to pass it by reference, so no copy is made.
I am learning C++ and was reading copy constructor from the C++: The Complete Reference. The books says that
It is permissible for a copy constructor to have additional parameters as long as they have default arguments defined for them. However, in all cases the first parameter must be a reference to the object doing the initializing.
But I am confused that how we are going to pass those additional parameters? I am sure there should be some way which is not given in the book and which I am unable to figure out. Can anyone help me out?
EDIT:
Also is it possible to pass these extra parameters in all three cases i.e.
When one object explicitly initializes another, such as in a declaration
When a copy of an object is made to be passed to a function
When a temporary object is generated (most commonly, as a return value)
Here is a simple example:
class A {
//...
public:
A (const A&, bool deep = false) {
if (!deep) { /* make a shallow copy */ }
else { /* make a deep copy */ }
}
};
void foo (A x) { /*...*/ }
A bar () { /*...*/ return A(); }
A a_var;
In this example, the parameter is defaulted to false, meaning the default copy constructor will be shallow.
A b(a_var); // b gets a shallow copy of a
foo(b); // foo() receives a shallow copy
However, it would be possible to effect a deep copy by passing in true in the second parameter.
A b(a_var, true); // b gets a deep copy of a
foo(A(b, true)); // foo receives a shallow copy of a deep copy
Similarly, for a function returning an A, the returned copy would be shallow, since it is using the default, but the receiver can make it deep when it receives it.
A b(bar()); // shallow
A b(bar(), true); // deep
Remember when you define a copy constructor, it is likely to mean you will need to define a destructor and overload the assignment operator (the rule of three).
Think of it this way: there is only the notion of constructor. When the compiler decides a copy needs to be made, it looks for a constructor that can be called by passing in a single object of type T. Because of this special use case, we conventionally call the constructor chosen a "copy" constructor.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why should the copy constructor accept its parameter by reference in C++?
i know that a copy constructor must have a reference as a parameter, to avoid an 'infinite number of calls' to itself. my question is - why exactly that happens, what is the logic behind it?
CExample(const CExample& temp)
{
length = temp.length;
}
assume your argument to the copy C'tor was passed by value, the first thing the C'tor would have done, was copying the argument [that's what every function, including constructors do with by-value arguments]. in order to do so, it would have to invoke the C'tor again, from the original to the local variable... [and over and over again...] which will eventually cause an infinite loop.
Copy constructors are called on some occasions in C++. One of them is when you have a function like
void f(CExample obj)
{
// ...
}
In this case, when you make a call
CExample x;
f( x );
CExample::CExample gets called to construct obj from x.
In case you have the following signature
void f(CExample &obj)
{
// ...
}
(note that obj is now passed by reference), the copy constructor CExample::CExample does not get called.
In the case your constructor accepts the object to be copied by value (as with the function f in the first example), compiler will have to call the copy constructor first in order to create a copy (as with the function f, again), but... oops, we have to call the copy constructor in order to call the copy constructor. This sounds bad, doesn't it?
See here
"It is a reference because a value parameter would require making a copy, which would invoke the copy constructor, which would make a copy of its parameter, which would invoke the copy constructor, which ... "
Or put a different way a value parameter to the constructor would have to call the constructor to copy the value in the parameter. This new constructor would need to do the same - leading to infinite recursion!
I have a copy constructor that looks like this:
Qtreenode(const QtreeNode * & n) {
x=n->x;
y=n->y;
height=n->height;
width=n->width;
element=n->element;
}
I wrote this a week ago, and I looked back at it today and I was surprised by the line that when called the copy constructor with say swChild=new QtreeNode(*(n->swChild)); The arguement to the cc is a pointer by reference, right? But when I call it, I do (*(n->swChild)), which means the value of that child right? Why does my code work?
That is not a copy constructor. A copy constructor for a class is a constructor that takes a reference of the class's type. Any of the following would be copy constructors, though the second, taking a const reference, is by far the most commonly used:
QTreeNode(QTreeNode&);
QTreeNode(const QTreeNode&);
QTreeNode(volatile QTreeNode&);
QTreeNode(const volatile QTreeNode&);
Since this isn't a copy constructor, the implicitly declared copy constructor is still provided. It is declared as QTreeNode(const QTreeNode& n) and basically just copies each member of the class (i.e., it's a "shallow" copy, not a "deep" copy). It is this implicitly declared copy constructor that is used in your code.
That's not a copy constructor, it's just a regular old constructor. A copy constructor would take a const QtreeNode&, not a const QtreeNode*&.
Since you didn't define a copy constructor, the compiler made one for you. That's the one that is being called in the line swChild=new QtreeNode(*(n->swChild));, since you are passing a QtreeNode and not a pointer to one.
Can I write a copy constructor by just passing in a pointer instead of the const reference? (Would it be ok if I make sure that I am not going to change any values though?)
Like so:
SampleClass::SampleClass(SampleClass* p)
{
//do the necessary copy functionality
}
instead of:
SampleClass::SampleClass(const SampleClass& copyObj)
{
//do the necessary copy
}
Thanks in advance.
Thanks everyone. So, if I write a constructor that takes in a pointer( and thought that's my copy constructor), the compiler would still supply with the default copy constructor in which case my constructor( which i thought was my copy constructor) would not be called and the default copy constructor would be called. Got it.
Yes, you can write a constructor that takes a pointer to the object. However, it cannot be called a copy constructor. The very definition of a copy constructor requires you to pass an object of the same class. If you are passing anything else, yes, it's a constructor alright, but not a copy constructor.
You can write a constructor that takes a pointer as an argument.
But the copy constructor is the name we give a specific constructor.
A constructor that takes a reference (preferably const but not required) of the same class as an argument is just named the copy constructor because this is what it effectively does.
Besides the fact that it would not be a copy constructor and the compiler will generate the copy constructor unless you explicitly disable it, there is nothing to gain and much to loose. What is the correct semantics for a constructor out of a null pointer? What does this add to the user of your class? (Hint: nothing, if she wants to construct out of a heap object she can just dereference the pointer and use the regular copy constructor).
No. Copy constructors must take a reference, not pointer, if it's to be useful for passing-by-value, etc.
By definition, the copy ctor uses a const reference. While there is nothing stopping you from writing a ctor that takes a pointer, it raises some problems not present when using a reference - e.g., what should/can happen if a null pointer is passed in?
A copy constructor needs a reference because a value parameter would require making a copy, which would invoke the copy constructor, which would make a copy of its parameter, which would invoke the copy constructor, which ...
You can write a constructor like that but its not technically a copy constructor. For example the STL containers will still use the compiler generated copy constructor (the compiler generates one because you didn't write one).
The copy constructor is implicitly used in two cases:
When an instance of your class is passed by value to a function.
When an instance of your class is returned by value from a function.
As others have mentioned, you can write a constructor with the signature described (or with a const pointer), but it would not be used in either of the above cases.
You can write a perfectly valid copy constructor, and still be able to pass a reference that is NULL. You can test for NULL, but only if you do not use constructor initialization lists.
Example:
MyClass::MyClass( MyClass const& MyClassCopy )
: somevar( MyClassCopy.somevar ) // <- the init list goes here.
{
// If MyClassCopy is NULL, the initialization above is doomed!
// However we can check for NULL in the constructor body but
// the initialization list must be removed ...
if (&MyClassCopy == NULL ) throw( std::runtime_error("NULL pointer!"));
somevar = MyClassCopy.somevar;
}
// I'll now do some very dangerous programming to
// demonstrate one way that a NULL can get through ...
MyClass* P = NULL;
MyClass A( *P ); // Bang, you're dead!
As far as I know, there's no way to check for a NULL from inside the initialization list, so if you think you could end up with a situation where a NULL gets through, you have to test for it in the constructor body and do the initializing from there.
Don't forget there's a few gotchas with ::operator=() function to be aware of ...