C++ Copy Constructor - 指针分段错误的深拷贝

C++ Copy Constructor - Deep Copy of Pointers Segmentation Fault

我最近开始通过高级计算机科学基础 MOOC 学习 C++。我们有一个在隐藏的 .h 文件中声明的挑战(无法更改),我们需要对在 .h 文件中初始化的所有成员 functions/constructors/destructor 进行编码。

为了避免作弊或任何人为我工作,如果有人能帮助解释我做错了什么以及我正在做什么来获得分段错误,我将不胜感激。我搜索并搜索了所有深拷贝指南和浅拷贝指南,但似乎无法理解我在这方面做错了什么。

这是 .h 文件:

  class Pair {
    public:
      int *pa,*pb;
      Pair(int, int);
      Pair(const Pair &);
      ~Pair();
   };

从这里要指出的两件事是 pa/pb 是指向整数的指针,而不仅仅是整数,并且即使我读到 "Rule of the Big Three" 也没有赋值运算符的位置解释了如果我有复制构造函数或析构函数,我也应该有赋值运算符。

继续前进,我尝试了很多方法来让它工作并包含大量诊断消息,并且可以看到我搞砸的地方但无法理解为什么或我应该做什么。

自定义构造函数 我觉得还可以:

 Pair::Pair (int a,int b) {
      int *pa = new int(a);
      int *pb = new int(b);
      std::cout << "pa points to value : " << *pa <<std::endl;
      std::cout << "pb points to value : " << *pb <<std::endl;
      std::cout << "custom constructor resolved "<<std::endl;
    }

复制构造函数 请原谅我只是想解决问题的所有评论。

    Pair::Pair(const Pair &obj) {

    int *const * a = &obj.pa;
    int *const * b = &obj.pb;
    int *pa = new int;
    int *pb = new int;
    pa = *a;
    pb = *b;

    std::cout << "obj.pa address is : " << &obj.pa <<std::endl;
    std::cout << "obj.pb address is : " << &obj.pb <<std::endl;
    std::cout << "obj.pa points at : " << obj.pa <<std::endl;
    std::cout << "obj.pb points at : " << obj.pb <<std::endl;

    std::cout << "pa address is : " << &pa <<std::endl;
    std::cout << "pb address is : " << &pb <<std::endl;
    std::cout << "pa is pointing at : " << pa <<std::endl;
    std::cout << "pb is pointing at : " << pb <<std::endl;
    std::cout << "copy constructor called "<<std::endl;
     }

析构函数 我认为我在这方面做得还不错:

    Pair::~Pair() {
      delete pa; pa = nullptr;
      std::cout << "pa deleted " << std::endl;

      delete pb; pb = nullptr;
      std::cout << "pb deleted " << std::endl;
    }

主要 系列测试

int main() {
  Pair p(15,16);
  Pair q(p);
  Pair *hp = new Pair(23,42);
  delete hp;

  std::cout << "If this message is printed,"
    << " at least the program hasn't crashed yet!\n"
    << "But you may want to print other diagnostic messages too." << std::endl;
  return 0;
}

看这个程序会创建一对p;然后创建一个深拷贝对q;然后创建一个指向堆上的一对 23,42 的 hp 对指针;然后删除指向对 hp 的指针。除了复制构造函数之外,一切似乎都可以正确编译和运行。主要问题是 &obj.pa 似乎只是拉取对象 obj 的指针 *pa 指向的地址,而不是检索实际的取消引用值。

有关附加信息,这里是执行 .main 时的终端输出(添加附加注释):

pa points to value : 15            // pair p.pa correct
pb points to value : 16            // pair p.pb correct
custom constructor resolved        // pair p made
obj.pa address is : 0x7fff1887c780 // address original object pointer pa stored 
obj.pb address is : 0x7fff1887c788 // address original object pointer pb stored
obj.pa points at : 0x2             // address pointer obj pa is directed to (I want the value not this)
obj.pb points at : 0x40102d        // address pointer obj pb is directed to (I wand the value not this)
pa address is : 0x7fff1887c728     // pa address on stack
pb address is : 0x7fff1887c730     // pb address on stack
pa is pointing at : 0x2            // address value copied not address itself
pb is pointing at : 0x40102d       // address value copied not address itself
copy constructor called            // copy constructor runs through albeit incorrect
pa points to value : 23            // hp.pa
pb points to value : 42            // hp.pb
custom constructor resolved        // constructor made on heap from pointer hp
pa deleted deleted original pa     // (made from pointer to pair hp)
pb deleted deleted original pa     // (made from pointer to pair hp)
If this message is printed, at least the program hasn't crashed yet!
But you may want to print other diagnostic messages too.
pa deleted                         // deleted original pa (made from pair p)
pb deleted                         // deleted original pb (made from pair p)

我 运行 通过并在所有执行后得到 'Segmentation Fault' 我不太明白。在 C++ 学习这么早的时候,我什至对我的术语来帮助我的搜索能力没有信心。

您有两个重大错误。

首先,您要在构造函数中重新声明指针。

Pair::Pair (int a,int b) {
    int *pa = new int(a);
    int *pb = new int(b);
    ...

应该是

Pair::Pair (int a,int b) {
    pa = new int(a);
    pb = new int(b);
    ...

通过重新声明指针,您将指针隐藏在要分配给的 class 中,而是分配给仅存在于构造函数中的局部变量。

复制构造函数中存在完全相同的问题。

其次,当您执行复制构造函数时,您没有复制右侧指针的内容。您正在复制指针本身。

实际上比这容易得多,只需修改其他构造函数中的代码即可。

Pair::Pair(const Pair &obj) {
    pa = new int(*obj.pa);
    pb = new int(*obj.pb);

与其他构造函数中的代码相同,只是我们使用 obj 中的值而不是参数中的值初始化整数。

或者如果您喜欢更小的步骤

Pair::Pair(const Pair &obj) {
    int a = *obj.pa;
    int b = *obj.pb;
    pa = new int(a);
    pb = new int(b);