Copy constructors - c++ - c++

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

Related

Arguments for the copy constructor

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.

Copy constructor in private class Syntax

in 2 hours I'll take an exam on C++ and I'm still wondering about the syntax of the copy constructor.
So far what I understand is that you put the CopyConstructor in private so that when some function or whatever wants to copy your class it is not going to work because it will no have access to private variables. So you can check if you missed any pointers that will only make a shallow copy.
So far so good.
Now the syntax as I read it is
ClassName(const ClassName &)
and I wondered why you have that ampersand and the const in there. Would not just ClassName(ClassName) be enough?
From [class.copy]/2 in C++14:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments .
So your suggestion would not be a copy-constructor, according to the definition of the language.
In fact your suggestion is ill-formed according to [class.copy]/6:
A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments.
In order to pass something by value, you need to be able to make a copy of it. How do we make a copy? The copy constructor of course! So if we define the copy constructor like ClassName(ClassName), we pass in a ClassName, call the copy constructor, which calls the copy constructor which...
This results in infinite recursion; not a very reasonable way of copying an object. That is why we pass by reference: so we don't need to make any other copies. The const is there because copying an object shouldn't modify it, otherwise you get something horrific like auto_ptr.
Additionally, with C++11 it is preferred to use =delete to stop people copying your class rather than making the copy constructor private:
ClassName (const Classname&) = delete;
const means you can also make a copy of a class that is constant (and you make the promise that you will not modify the class that you're copying.
The ampersand & means your copy constructor takes a reference to the thing it's trying to make a copy of (without the ampersand it would get a copy of it, which is impossible as we're actually trying to make a copy).
The syntax f(Classname) means that the argument is copied, while f(const Classname&) makes a reference to the argument.
It would however be quite bad to copy the argument which is provided to the copy constructor, which should define how such a copy is made...
I wondered why you have that ampersand and the const in there
The ampersand means that the object to copy is passed by reference. The const means that the reference can't be used to modify it; which is what you'd expect when copying it.
Would not just ClassName(ClassName) be enough?
That would mean the object is passed by value. To do that, it would have to be copied. To copy it, you'd have to call the copy constructor. To do that, you'd have to pass the object by value. To do that, it would have to be copied. And so on.
So no, a copy constructor can't take its parameter by value.

copy-constructor related question (native c++) [duplicate]

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!

Pointer in copy constructor

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 call a copy constructor explicitly?

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