I am reading effective C++ in Item 5, it mentioned two cases in which I must define the copy assignment operator myself. The case is a class which contain const and reference members.
I am writing to ask what's the general rule or case in which I must define my own copy constructor and assignment operator?
I would also like to know when I must define my own constructor and destructor.
Thanks so much!
So, we need to define our own copy constructor only if an object has pointers or any runtime allocation of the resource like filehandle, a network connection, etc. The default constructor does only shallow copy. Deep copy is possible only with a user-defined copy constructor.
If a class do not have any pointers, then we do not need to create assignment operator and copy constructor. C++ compiler creates copy constructor and assignment operator for each class. If the operators are not sufficient, then we have to create our own assignment operator.
When should we write our own assignment operator in C++? The answer is same as Copy Constructor. If a class doesn't contain pointers, then there is no need to write assignment operator and copy constructor. The compiler creates a default copy constructor and assignment operators for every class.
The difference between a copy constructor and an assignment operator is that a copy constructor helps to create a copy of an already existing object without altering the original value of the created object, whereas an assignment operator helps to assign a new value to a data member or an object in the program.
You must create your own copy constructor and assignment operator (and usually default constructor too) when:
vector
Consider the following code:
class A; // defined elsewhere
class B {
private:
A *my_very_own_a;
};
If you let the automatic copy constructor copy a B
, it will copy the A *
pointer value across, so that the copy points to the same A
instance as the original. But part of the design of this class is that each B
has its own A
, so the automatic copy constructor has broken that contract. So you need to write your own copy constructor which will create a new A
for the new B
to point to.
However, consider this case:
class A; // defined elsewhere
class B {
private:
A *shared_reference_to_a;
};
Here each B
contains a pointer to an A
, but the class contract doesn't demand a unique A
for each B
. So the automatic copy constructor might well do the Right Thing here.
Note that both examples are the same code, but with different design intent.
An example of the first situation might be B
== dialog box, A
== button. If you create a copy of a dialog box, it probably needs a copy of all the contents too.
An example of the second might be B
== dialog box, A
== reference to window manager. If you copy a dialog box, the copy probably exists in the same window manager as the original.
The default copy constructor often causes two objects to "point to" a common piece of memory. This is because all the default copy constructor does is memberwise assignment. So if you have a pointer member, this can get you into trouble
CClass::CClass(const CClass& src)
{
// these two point to the same place in memory now
// you really aught to allocate new memory
m_ptr = src.m_ptr;
// not a big deal for members that aren't "pointing" elsewhere
// this copy works great
m_int = src.m_int;
}
You essentially don't want to end up in a situation where two instances are "pointing to" the same place in memory. This can happen when you have pointers as members which point to dynamically allocated memory. This can also happen with references, both referring to something outside the class itself. This can happen with file handles, where you may need to duplicate/reopen a new file.
In fact, the latter case is probably the easiest to conceptualize. Pretend your 2 C++ objects both had a log file. Without a correctly functioning copy constructor, they could both be logging to the same file. What happens if in the classes destructor, the file is closed out? Well then the 2nd C++ object will have it's log file closed out from underneath him. One solution would be to create a copy-constructor that creates a new file for the newly constructed instance. So when the 1st C++ object goes away, it doesn't take the 2nd C++ object's log file with it. They have 2 independent log files, they can't interfere with each other.
This example can be extended to dynamic memory. Without a copy constructor, you will just have 2 pointers pointing to the same address. If the destructor of one deletes that memory, the other might not realize that the memory it's pointed to has gone away. Equally important, you probably don't want one object writing into the other object's member :).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With