Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I define my own copy ctor and assignment operator

Tags:

c++

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!

like image 994
skydoor Avatar asked Feb 27 '10 15:02

skydoor


People also ask

When should we write our own copy constructor?

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.

When should we write our own assignment operator in C++?

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 it becomes necessary to define our own assignment operator and copy constructor explain with proper example?

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.

What is the difference between a copy constructor and an assignment operator?

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.


2 Answers

You must create your own copy constructor and assignment operator (and usually default constructor too) when:

  • You want your object to be copied or assigned, or put into a standard container such as vector
  • The default copy constructor and assignment operator will not do the Right Thing.

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.

like image 116
Philip Potter Avatar answered Sep 28 '22 12:09

Philip Potter


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

like image 32
Doug T. Avatar answered Sep 28 '22 11:09

Doug T.