The last assignment doesn't call the copy constructor, it calls the assignment operator.
The implementation of the copy constructor and the assignment operator can be something like:
Test(const Test& rhs)
{
p = new int;
*p = *rhs.p;
}
Test& operator= (const Test& rhs)
{
if (!p)
{
p = new int;
}
*p = *rhs.p;
return *this;
}
In addition to that, you can consider an implementation of the move constructor and the move assignment operator (C++11) too:
Test(Test&& rhs)
{
p = rhs.p;
rhs.p = nullptr;
}
Test& operator= (Test&& rhs)
{
if (p)
{
delete p;
}
p = rhs.p;
rhs.p = nullptr;
return *this;
}