c++ - 包含指向指针的对象的深层副本
问题描述
我正在尝试为包含指针的对象创建一个复制构造函数,该指针引用其他指针等。以下代码是二叉树。
B树.h
{
public:
vertex* root;
BTree()
{
root = NULL;
};
~BTree() {
delete root;
root = nullptr;
};
BTree(const BTree& p_BTree) //copy constructor
{
root = new vertex(*p_BTree.root);
}
BTree& operator= (const BTree& other) //assignment operator
{
// Delete the existing class A instance
delete root;
// and create a new as a copy of other.attribute
root = new vertex(*other.root);
}
节点.h
class vertex{
public:
int key;
string data;
vertex* leftChild;
vertex* rightChild;
vertex* parent;
int height;
vertex(string data){
key = ID;
this->data = data;
leftChild = NULL;
rightChild = NULL;
parent = NULL;
ID++;
};
vertex(){
key = 0;
leftChild = NULL;
rightChild = NULL;
parent = NULL;
};
vertex(vertex* node){
key = ID;
leftChild = node->leftChild;
rightChild = node->rightChild;
parent = node->parent;
};
~vertex(){
delete leftChild;
delete rightChild;
leftChild = nullptr;
rightChild = nullptr;
};
void print(string indent){
string indent2 = indent;
cout <<indent << " " << data <<endl;
if(leftChild != nullptr || rightChild != nullptr)
{
if(leftChild != nullptr){
indent = "|" + indent;
leftChild->print(indent);
}else{
cout << indent << endl;
}
if(rightChild != nullptr){
indent2 = "|" + indent2;
rightChild->print(indent2);
}else{
cout << indent2 << endl;
}
}
}
};
#include "BTree.h"
int main() {
// Aufgabe 1
BTree B;
B.main();
// Aufgabe 2
BTree C = B; //Call copy constructor
C.print();
// Aufgabe 3
BST D;
D.main();
D.print(D.root);
D.sortvector(); //neu hinzugefügt
// Aufgabe 4
D.PrintLayers(D.root, 1);
}
问题是,当调用析构函数时,程序会崩溃,因为它试图释放已经被释放的内存。
对象 B 和 C 中的根(在 main 中)具有不同的内存地址,问题是对象 C 中的左子和右子。这些是浅拷贝而不是深拷贝。我不知道如何在这些属性的复制构造函数中执行此操作。
这是它在调试器中的样子:
解决方案
我没有时间检查您的完整代码。
但是如果是,root = new vertex(*p_BTree.root);
在你的复制构造函数中会是一个问题。root
nullptr
并且您vertex
管理资源(它delete
在析构函数中有一个),但不遵循三/五规则。
因此,一旦vertex
创建了实例的副本,就会复制指针,并且两个实例vertex
管理相同的指针,从而导致双重释放。
在树的节点中使用它是有问题的:
~vertex(){
delete leftChild;
delete rightChild;
leftChild = nullptr;
rightChild = nullptr;
};
如果你有一棵深度很大的树,你可能会遇到 stackoverflow。这样做的原因是因为删除是递归完成的。您想在根中收集树的节点并在那里删除它们。
复制构造函数和复制赋值运算符中的深度复制也是如此vertex
。
进一步说明:
root = nullptr;
在析构函数之后做delete
是你不需要做的事情。对vertex
.- 保持一致,不要混用
NULL
andnullptr
。你应该坚持nullptr
。 root = NULL;
在您的构造函数中应该使用成员变量的默认值或通过构造函数的成员初始化器列表来完成。对vertex
.
推荐阅读
- r - 从包含列中的数字和字母的字符串中删除数字字符(在R中)
- crystal-reports - 将 sap b1 中标准选择中没有值的字段传递给水晶报告
- python - 为什么 pyinstaller 创建的可执行文件不起作用?
- javascript - 如何创建用于在字符串中查找电子邮件地址的 JavaScript 正则表达式?
- postgresql - 从 AIX Oracle 到 Postgresql 的 DBLink
- signalr - Signalr Hub 中的后台任务
- ios - iOS 收到远程通知时,我们能知道它并做些什么吗?
- javascript - 无法导入 MongoClient
- scrapy - Scrapy将所有文本提取到一个单元格中如何划分?
- sql - 在 postgres 中使用 CTE 进行更新插入