使用复制构造函数修复浅拷贝

fixing shallow copy with a copy constructor

我定义了一个复制构造函数以避免对数据成员 n 进行浅表复制,但它不起作用,当我更改 v1 时 v2 仍在更改,我做错了什么?

#include<iostream>
using namespace std;
class Vector
{
  public:
  int *n;

  Vector();
  Vector(const Vector& vector );

};
Vector::Vector()
{
  cout<<"Constructor called"<<endl;
}
Vector::Vector(const Vector& vector )
{
  n=new int;
  n=vector.n;
  cout<<"Copy constructor called"<<endl;
}



int main()
{
  Vector v1;
  int x=5;
  v1.n=&x;
  Vector v2=v1;

  cout <<"Vector v1 has n value: "<<*v1.n<<endl;
  cout <<"Vector v2 has n value: "<<*v2.n<<endl;
  *v1.n=499; 
  cout <<"Vector v1 has n value: "<<*v1.n<<endl;
  cout <<"Vector v2 has n value: "<<*v2.n<<endl;

  return 0;
}


问题是你的复制构造函数实现错误。您尝试修复浅拷贝问题,但您的代码包含一个声明,该声明再次重新引入相同的问题。

这一行:

n=new int;

您正确地分配了一个新的 int,没问题。

但是在这条线上:

n=vector.n;

您正在丢弃刚刚分配的 int,而是将 n 指向另一个向量的 n 指向的相同 int。这又是浅拷贝问题。

要正确解决此问题,您需要将另一个向量的 n 成员的值 复制到新分配的 n 成员中,例如:

n = new int;
*n = *(vector.n);

或:

n = new int( *(vector.n) );

也就是说,要完全符合 "Rule of 3",您还需要添加一个析构函数来释放 n(这意味着您 不能 使 v1 指向 main() 中的局部 int 变量),以及添加复制赋值运算符以复制 n(类似于复制构造函数)。在 C++11 中,您还可以选择通过添加移动构造函数和移动赋值运算符来遵守 "Rule of 5"。

试试这个:

#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;
}