提问人:jmdatasci 提问时间:3/22/2020 更新时间:3/22/2020 访问量:540
C++ 复制构造函数 - 指针分段错误的深度复制
C++ Copy Constructor - Deep Copy of Pointers Segmentation Fault
问:
我最近开始通过高级计算机科学基础MOOC学习C++。我们有一个在隐藏的 .h 文件中声明的挑战(无法更改),我们需要对 .h 文件中初始化的所有成员函数/构造函数/析构函数进行编码。
为了避免作弊或任何人为我做这项工作,如果有人能帮助解释我做错了什么以及我做了什么来获得分段错误,我将不胜感激。我已经搜索并搜索了所有深度与浅层的复制指南,但似乎无法理解我做错了什么。
下面是 .h 文件:
class Pair {
public:
int *pa,*pb;
Pair(int, int);
Pair(const Pair &);
~Pair();
};
从中需要指出的两件事是,pa/pb 是指向 int 的指针,而不仅仅是 ints,并且没有赋值运算符的位置,即使我读到了“三巨头规则”,它解释了如果我有复制构造函数或析构函数,我也应该有赋值运算符。
继续前进,我尝试了很多事情来让它工作,并包含大量的诊断信息,可以看到我在哪里搞砸了,但不明白为什么或我应该做什么。
自定义构造函数我认为这没关系:
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;
}
Copy 构造函数请原谅我刚刚试图排除故障的所有评论。
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)
我跑了一遍,在执行之后得到了我不太理解的“分段错误”。而且在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);
...
通过重新声明指针,您将隐藏要分配给的类中的指针,而是分配给仅存在于构造函数中的局部变量。
复制构造函数中存在完全相同的问题。
其次,在执行复制构造函数时,您不会复制右侧指针的内容。您正在复制指针本身。
它实际上比这容易得多,只需从其他构造函数调整代码即可。
Pair::Pair(const Pair &obj) {
pa = new int(*obj.pa);
pb = new int(*obj.pb);
与其他构造函数中的代码相同,只是我们使用 from 的值而不是参数中的值初始化整数。obj
或者,如果您喜欢较小的步骤
Pair::Pair(const Pair &obj) {
int a = *obj.pa;
int b = *obj.pb;
pa = new int(a);
pb = new int(b);
评论
obj.,pa
obj.pb
评论