为什么以及何时应该在C ++中使用Copy Constructor?为什么不鼓励浅拷贝呢?

时间:2010-02-21 11:38:55

标签: c++ constructor

让我们说我们创建一个类Student的对象,我们创建两个实例/对象类Student(即StudentA和StudentB)。我们使用浅层复制来初始化B的数据成员,如下所示:

学生B =学生A;

然后我们摧毁了StudentB。我们在这里面临悬空指针的情况吗?为什么以及如何?请解释一下。

4 个答案:

答案 0 :(得分:5)

  

我们在这里遇到悬空指针的情况吗?为什么以及如何?请解释一下。

这取决于学生的实施。如果学生看起来像这样......

class Student
{
public:
  char* m_name;
  Student(const char* name)
  {
    m_name = new char[strlen(name)+1];
    strcpy(m_name,name);
  }
  ~Student()
  {
    delete[] m_name;
  }
};

...然后有一个问题:当你复制一个学生时,你有两个指向相同m_name数据的指针,当两个学生实例被删除时,m_name数据被删除两次,这是非法的。为了避免这个问题,Student需要一个显式的复制构造函数,以便复制的Student有一个指向不同m_name数据的指针。

或者,如果学生看起来像这样......

class Student
{
public:
  std::string m_name;
  Student(const char* name)
    : m_name(name)
  {
  }
};

...然后没有问题,因为魔法(即显式复制构造函数)是在std :: string类中实现的。

总之,如果类包含分配和删除的指针,则需要显式的复制构造函数(或者显式没有复制构造函数,但在任何一种情况下,不仅仅是默认构造函数)。

答案 1 :(得分:3)

并不劝阻浅版,确切地说 - 这是知道什么时候合适的问题。

这里的问题是“所有权”之一。 “Student”类是否“拥有”指向的数据,因此负责(在其析构函数中)删除该数据。

基本上,如果您获取拥有某些指向数据的对象的浅表副本,然后销毁原始数据或副本,则删除指向数据(由析构函数删除)。但是你仍然在对象中有一个没有被破坏的引用 - 一个悬垂的指针。

OTOH,如果对象不拥有指向的数据,析构函数不会删除指向的数据,并且没有问题。虽然你必须确保某些东西拥有指向的数据,否则你会有内存泄漏。

跟踪指向数据的所有权是非垃圾收集语言(如C ++)的关键技能,是应用Resource Allocation Is Initialisation模式的基础。

答案 2 :(得分:1)

简单来说: 如果您的类成员变量包含它也拥有的指针。

答案 3 :(得分:1)

另一点是成员的指向数据是不可变的。通过使用引用计数智能指针在实例之间共享它是不可观察的。例如,我有一些看起来像

的代码
struct SizeContainer {
  // ... stuff ...
private:
  boost::shared_ptr<SizeExpression> p;
};

我没有声明复制构造函数和复制赋值运算符,因为无论如何都无法更改p,因此它可以在多个实例之间共享。