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);
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.
class A { ... };
A& getA();
A anA = getA();
What happens exactly on line 3 ?
Is the copy constructor of A called, thus creating an object independent from the one returned (by reference) by the function?
Is the copy constructor of A called, thus creating an object independent from the one returned (by reference) by the function?
Yes. The copy constructor takes a reference to the source object as it's parameter and a copy is independent of the original object assuming the copy constructor does a deep copy.
I will gladly change the title of this thread to something more appropriate once I know what subject this falls under.
If I change the parameters of the error-causing constructor, there is no error.
This error only occurs if I include that exact constructor:
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
Code:
#include <iostream>
using namespace std;
class Object {
public:
Object() {} /* default constructor - no problems at all */
Object( Object & toCopy ) {} /* Cause of error, but no error when commented out */
Object func() {
Object obj;
return obj;
}
};
int main() {
Object o = o.func(); /* this is the line that the error is actually on */
return 0;
}
You have declared an unusual and terrible copy constructor, namely one which takes the argument by non-constant reference. This is possible, and it means that no other copy constructor will be defined implicitly. However, it also means that you cannot construct copies from temporary values, since those don't bind to non-constant references.
Unless you had a reason to do what you were doing (maybe you want to define auto_obj :-) ?), you should declare the usual copy constructor with argument Object const & (but make sure to define it correctly!), or just leave it out entirely and rely on the implicitly generated version (as happens when you "comment out the line" in your code); or in C++11 you can default the copy constructor by declaring Object(Object const &) = default;.
(Note that the popular Rule of Three says that you either should not be defining your own, non-trivial copy constructor, or if you do, then you also need a user-defined destructor and assignment operator. Make sure your code is sane.)
the error you got
error: no matching function for call to 'Object::Object(Object)'
note: candidates are: Object::Object(Object&)
note: Object::Object()
means that compiler is looking for appropriate copy constructor for class Object. There is no such function in your class definition: your version cannot be used to bind temporary (see below). The correct version might be defined by yourself with:
Object(const Object& orig) {
// and initialize data here, and return
}
or you can just don't declare such function, and working version will be generated automatically, thus there is no error then as well.
note:
you are trying to define Object( Object & toCopy ) {}. This is not correct because taking non-const reference to temporary means you cannot use this temporary object to create a copy from it in your constructor because temporary objects cannot be assigned to non-const reference.
So to express this diferent way:
-> compiler is searching for copy constructor
-> finds your version
-> and this version tells: I will not do it
Finally:
Object o = o.func();
this is not good idea. Referring to nonstatic members of objects that have not been constructed or have already been destructed is undefined behavior. Make func() static so might be used like Object::func() or call it on properly constructed object.
Try Object(const Object &toCopy) { }
As already pointed out by many previously, the problem is that you only defined a copy constructor taking a reference, but the return of the call of o.func(); is an rvalue, which can only bind to rvalue references or const references, not to regular references.
Your code however has another issue, calling func() on o, which at that point is a yet uninitialized object, is a very bad idea. Maybe you intended to implement the factory idiom? In this case I would advise that you declare Object func(); static, and call it from the scope of Object, like so:
Object o = Object::func();
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.
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 ...