The problem is that your copy constructor is implemented wrong. You try to fix the shallow copy issue, but your code includes a statement that re-introduces the same issue again.
On this line:
n=new int;
You correctly allocate a new int
, which is fine.
But on this line:
n=vector.n;
You are throwing away the int
you just allocated, and instead point n
to the same int
that the other vector's n
points to. This is the shallow copy issue all over again.
To fix the issue properly, you need to copy the value of the other vector's n
member into your newly allocated n
member, eg:
n = new int;
*n = *(vector.n);
Or:
n = new int( *(vector.n) );
That being said, to fully comply with the "Rule of 3", you also need to add a destructor to free n
(which means you can't make v1
point to a local int
variable in main()
), as well as add a copy assignment operator to copy the value of n
(similar to the copy constructor). In C++11, you can optionally also comply with the "Rule of 5" by adding a move constructor and move assignment operator, as well.
Try this instead:
#include <iostream>
#include <utility>
//using namespace std; // <-- bad practice!
class Vector
{
private:
int *m_n;
public:
Vector(int x = 0);
Vector(const Vector &src);
Vector(Vector &&src);
~Vector();
Vector& operator=(const Vector &src);
Vector& operator=(Vector &&src);
// alternatively, both operators can be merged into one:
// Vector& operator=(Vector src);
// you should not give outside code directly access to the int* itself,
// that would promote bad practices, and potentially crash your class's
// internal code if outside code assigns a bad pointer.
//
// these accessors provide safer use of the *value* that the int* points
// at, let the class itself be the sole handler of the int* itself ...
int n() const;
void n(int x);
};
Vector::Vector(int x)
: m_n( new int(x) )
{
std::cout << "Converting Constructor called" << std::endl;
}
Vector::Vector(const Vector &src)
: m_n( new int(src.n()) )
{
std::cout << "Copy constructor called" << std::endl;
}
Vector::Vector(Vector &&src)
: m_n( src.m_n )
{
src.m_n = nullptr;
std::cout << "Move constructor called" << std::endl;
}
Vector::~Vector()
{
delete m_n;
std::cout << "Destructor called" << std::endl;
}
Vector& Vector::operator=(const Vector &src)
{
if (&src != this) {
*m_n = src.n();
}
std::cout << "Copy assignment called" << std::endl;
return *this;
}
Vector& Vector::operator=(Vector &&src)
{
Vector tmp(std::move(src));
std::swap(m_n, tmp.m_n);
std::cout << "Move assignment called" << std::endl;
return *this;
}
/* alternatively:
Vector& Vector::operator=(Vector src)
{
std::swap(m_n, src.m_n);
std::cout << "Assignment called" << std::endl;
return *this;
}
*/
int Vector::n() const
{
return *m_n;
}
void Vector::n(int x)
{
*m_n = x;
}
int main()
{
Vector v1(5);
Vector v2 = v1;
std::cout << "Vector v1 has n value: "<< v1.n() << std::endl;
std::cout << "Vector v2 has n value: "<< v2.n() << std::endl;
v1.n(499);
std::cout << "Vector v1 has n value: " << v1.n() << std::endl;
std::cout << "Vector v2 has n value: "<< v2.n() << std::endl;
return 0;
}