This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why should the copy constructor accept its parameter by reference in C++?
Can a object be passed as value to the copy constructor
Consider this piece of code:
class complex{
private:
double re, im;
public:
complex(double _re, double _im):re(_re),im(_im){}
complex(complex c):re(c.re),im(c.im){}
};
When compiled, I got an error message: invalid constructor; you probably meant ‘complex (const complex&)’
In the book C++ Programming Language, it is written that:
The copy constructor defines what copying means – including what
copying an argument means – so writing
complex : complex(complex c) :re(c.re) , im(c.im) { } // error
is an error because any call would have involved an infinite recursion.
Why does this cause infinite recursion? It doesn't make sense.
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...
Passing by value (rather than by reference) means a copy needs to be made. So passing by value into your copy constructor means you need to make a copy before the copy constructor is invoked, but to make a copy you first need to call the copy constructor.
When a function is passed with a parameter, local variable is created corresponding to the parameter and is copied with the argument passed on to the function invocation. Hence when the function is invoked, copy constructor of the function will be invoked to copy the argument passed to the invocation to the local variable created. This results in a endless loop.
Where as when a reference is passed on to the function , local variable is not created corresponding to the parameter.
Related
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.
In C++ I have a constructor that accepts an object of class descriptor. This class has recently grown in size and I need to pass it by reference more. If I pass it by reference into the following ctor will the member still make its own copy given that it is not declared as a reference type?
descriptor taskedStats;
public:
CWorkerThread(int ticketNumber, int threadNumber, descriptor taskedStats) :
_pPaginatableForm(pPaginatableForm), ticketNumber(ticketNumber)
, threadNumber(threadNumber), taskedStats(taskedStats) {}
or
descriptor taskedStats;
public:
CWorkerThread(int ticketNumber, int threadNumber, descriptor &taskedStats) :
_pPaginatableForm(pPaginatableForm), ticketNumber(ticketNumber)
, threadNumber(threadNumber), taskedStats(taskedStats) {}
Your constructor will make a copy, whatever. If you pass by value then you could be making 2 copies, however the compiler is likely to optimise away one of them.
Still, the better option is to accept a const reference, i.e.
CWorkerThread(int ticketNumber, int threadNumber, descriptor const& taskedStats) :
_pPaginatableForm(pPaginatableForm),
_ticketNumber(ticketNumber),
_threadNumber(threadNumber),
_taskedStats(taskedStats)
{}
Of course once we enter the world of C++11 and move constructors you won't need to make any copies at all, as long as the one being passed in is no longer needed. There are ways to do that even now, but requires special "hacking" inside the object, or use of smart-pointers.
The class member is declared as an object, so an object it is.
The reference passed to the constructor will be used to initialise the member, using its copy constructor.
It's best to pass by const reference when you can; that makes it clear that the constructor won't modify the argument, and also allows you to pass a temporary value.
The change in parameter from descriptor to descriptor& will still result in the member variable taskedStats being copied (using copy constructor) from the argument taskedStats.
To avoid the copy you could make the member variable taskedStats a descriptor&, but this means that the argument taskedStats must be valid for the lifetime of the CWorkerThread object (in this case not making the argument taskedStats a const descriptor& would prevent the passing of temporary objects).
The default, or implicit, compiler-supplied copy constructor makes shallow copies of all members and would have the following signature:
descriptor(const descriptor &other);
so passing a reference to descriptor would be no different to attempting (in C parlance) to pass a copy- they would both in fact just be passed by reference.
If the member was declared as a reference type then, just as for pointers, its type wouldn't match in the above, implicit, copy constructor and a reference assignment would be performed, thuse invalidating any attempt to create a local copy in each object.
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'm a little confused as to the mechanics of the copy constructor. Correct me if I'm wrong:
If a method takes a reference to an object as a parameter, and the class defines a copy construtor, then the class uses the constructor to create a copy of itself and that gets passed to the function instead of a reference to the original object?
Furthermore, one can call
Object * obj = new Object(&anotherObject);
to create a copy of anotherObject?
No, if a function take a reference:
void f1( Object & o ); // call by reference
then no copy is made. If a function takes a value:
void f2( Object o ); // call by value
then a copy is created by the compiler using the copy constructor.
And yes, when you say:
Object * obj = new Object(anotherObject); // not &anotherObject
the copy constructor is used explicitly (assuming anotherObject is of type Object.) There is nothing magic about the use of new here, however - in this case:
Object obj2(anotherObject);
the copy constructor is also used.
If a method takes a reference to an object as a parameter, copy constructor will not be called. If that was the case, then a call to the copy constructor itself would have resulted in an infinite loop (since it takes a reference as an argument).
That line is not a valid way to call a copy constructor. It expects a reference as an argument, not a pointer.
The fact that you are making a method call is of no importance here. Reference parameter initialization during a function call is no different from a standalone reference initialization and is governed by the same rules.
The rules of reference initialization are a bit complicated, but the bottom line is that if the initializer is an lvalue (the argument in the method call in your case) and the type of the reference is the same as the type of the initializer (i.e. type of the parameter is the same as the argument type), then the reference will be bound directly. I.e. no copy is created.
Object a; // class type
Object &r = a; // no copying
const Object &cr = a; // no copying
If these requirements are not met (like if the initializer is an rvalue, for example), then it all depends. In some cases the copying might and will take place. For example
const Object &tr = Object();
can be interpreted by the compiler as
const Object &tr = Object(Object(Object(Object())));
with implementation-dependent finite number of copyings. Of course, for efficiency reasons compilers normally are trying not to create unnecessary copies, even when they are allowed to copy.
A classic example that often stirs debate about the validity of the copying behavior of the compiler is the reference initialization in expressions like the following one
Object a;
const Object &r = <some condition> ? a : Object();
A person familiar with C++ reference semantics would understand that expressions like the above are likely the rationale behind the standard permission to perform superfluous copying during reference initialization.
No in both the cases. In the first case, reference to that object itself is passed and copy is not created. In the second case you are passing a pointer to the constructor of object hence no copy is created. So object should have a constructor (not a copy constructor) which is something like object(anotherClass*)
Copy constructor is called only when passing by value, not by reference. By reference no copying is needed (this is part of what references are for!) so no copy constructor called.
yes using placement new like so:
Object dstObject;
new(&dstObject) Object(&anotherObject);
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 ...