Copy constructor with more than one parameter - c++

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.

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.

What are the benefits of using copy constructor?

I am new to object oriented programming, and this may be a silly question, but I don't understand why is using class A code better to use than class B if you want to create copy of one object.
class A {
int num;
public:
A(const A &ref) : num(ref.num) {};
};
class B {
int num;
public:
B(B *ptToClass) : num(ptToClass->num) {};
};
If I got this right, copy constructor is used in class A.
If you don't declare a copy constructor for your class, the compiler will declare one for you anyway. Classes have to have copy constructors. They're baked into the language and have special status. The language doesn't work without them.
Possibly the best example is that copy constructors are needed when passing by value. The compiler is going to implicitly call the copy constructor when you pass by value. It's not going to call the constructor B::B(B*).
So if you want your class to be copyable, you should define the copying logic in the copy constructor. It's just easier.
Class A is flexible and safe: you create a copy from any A object you have, even if it's a temporary one.
Class B is less safe as you could invoke the constructor with a nullptr. It's less flexible because you can only use ypur constructor to copy an object from which you can get the address and which is not const.
B b1(...);
const B b2(...);
B fb(); // function returning a B
B b3(&b1);
B b4(&b2); // error b2 is const
B b5(&fb()); // error you can't take adress of a temporary
The thing is that if a constructor is considered to be a copy constructor by the compiler, it is used in special ways. For instance, if you have a function that takes a parameter of your type A by copy, like this:
void function(A obj) {
// Do something with A
// ...
}
And then you call that function:
int main() {
A a_obj;
function(a_obj);
}
the object obj received by function will be created by the copy constructor you provided. So, it is a nice thing to provide copy constructor for your classes that are meant to be copied, so that them fits more nicely with the languages features and libraries.
There is no problem in creating a constructor of the kind in your class B, if that fit your needs in your application, but that will not be understood by the compiler as a copy constructor, and won't be used when the compiler or libraries needs to copy your objects.
It is forbidden by standard to use pointers in copy constructors:
C++ draft standard n3376 - section 12.8.2:
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
Why is the argument of the copy constructor a reference rather than a pointer?
I think a more appropriate question to ask is: when to provide a user-defined copy constructor over the default one provided by the compiler?
As we know, the compiler provides a copy constructor (the default one) which does a memberwise copy.
This memberwise copy is not bad as long as the class is a simple concrete type (that behaves for the most part like a built-in type). But for complex concrete types or classes with hierarchies, memberwise copy is not a good idea, and the programmer is highly advised to provide his own implementation of the copy constructor (that is, provide user-defined copy constructor).
As a thumb rule, it is a good idea to provide user-defined copy constructor in the class.

Why ampersand is used in copy constructor?

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.

How do you call the copy constructor within a member function of a class?

Here's what I've got:
void set::operator =(const set& source)
{
if (&source == this)
return;
clear();
set(source);
}
And here's the error I get:
vset.cxx:33: error: declaration of 'source' shadows a parameter
How do I properly do this?
You are looking for the copy swap idiom:
set& set::operator=(set const& source)
{
/* You actually don't need this. But if creating a copy is expensive then feel free */
if (&source == this)
return *this;
/*
* This line is invoking the copy constructor.
* You are copying 'source' into a temporary object not the current one.
* But the use of the swap() immediately after the copy makes it logically
* equivalent.
*/
set tmp(source);
this->swap(tmp);
return *this;
}
void swap(set& dst) throw ()
{
// swap member of this with members of dst
}
I believe with set(source); you are trying to call copy ctor. You can not do that in C++ i.e. you can not explicitly invoke the ctor. What you can do is write a private clone
method and call it in both copy ctor and assignment operator.
As you've noted, set(source); is the source (no pun intended) of the problem. This isn't doing quite what you think it is -- it's not attempting to invoke a copy ctor. Instead, it's basically equivalent to: set source; -- i.e. it's attempting to define a set object named source -- the parentheses are redundant but allowed.
You can invoke a copy ctor in a ctor (or just about anywhere you want to) but it's not going to to what you want anyway -- a copy ctor creates a copy, so even if you did invoke it, it would just create a temporary object, which would evaporate at the end of that statement.
As already mentioned, what you probably want is a private function to copy the data from one object to another, then use that from both your copy ctor and your copy assignment operator. Better still, define it using objects that can be handled correctly by the default copy ctor and copy assignment operators.
That error is usually the result of having a local variable named the same as a function argument. Can you post more of your code?
The error message you are seeing doesn't match the question, but I don't know that it is relevant. The answer to your question is that you cannot call the copy constructor from inside your code because the object is already constructed.
If you want to avoid code duplication between the copy constructor and operator=, I suggest having a private function that does the common work, and call that from both the copy constructor and operator=.
For reference, you could call operator= from copy constructor by doing:
*this = source;
However, I don't think that is a good idea especially if you have virtual functions or if the operator=() function assumes a fully constructed object (which it probably does).
I don't know the details of what your header file specifies, but I would try something like this (you may need to modify it for your specific application):
void set::operator =(const set& source)
{
if (this == &source)
{
return;
}
size_t i;
this->clear();
data=source.data;
for (i=0; i<source.child.size(); i++)
{
child.push_back(new set(*(source.child[i])));
}
}
-Joel

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