You should write your own copy constructor if you have a dynamically allocated object (like something allocated with new/new[]) because the default copy ctor will simply copy the point and not reallocate the buffer.
class C
{
public:
C() { p = newint; }
~C() { delete p; }
protected:
int* p;
};
void func_ok()
{
C a; // calls default ctor (a.p created with new)
} // calls dtor (a.p deleted)
void func_bad()
{
C a; // calls default ctor (a.p created with new)
C b(a); // calls copy ctor (b.p not allocated, but instead, b.p = a.p)
} // calls both dtors, so both a and b try to delete the same pointer (error/crash)
The same problem happens with the assignement operator.. so that should be overloaded as well in these types of cases. This is solved by writing a copy ctor and assignement operator overload:
1 2 3 4 5 6 7 8
class C
{
public:
// ...
C(const C& c) { p = newint; *p = *c.p; }
C& operator = (const C& c) { *p = *c.p; return *this; }
// ...
};
There are other uses for a copy ctor, as well. Like if you want to make an object that reference counts rather than completely copying a buffer or something.