【问题标题】:Delete keyword c++删除关键字 c++
【发布时间】:2020-08-08 21:57:45
【问题描述】:

我有一个有 2 个布尔值和一个指针数组的类,我在堆上分配。问题是当它调用析构函数时它给了我一个错误,可能是因为它删除了太多,我看到它试图访问 0xdddddd并向我展示这个“抛出异常:读取访问冲突。 这是 0xDEEEDEEF。”

1.如何更好地使用“删除”,是不是因为操作符重载?

2.还说我没有初始化“QuadTree::childs”,为什么?

class QuadTree {
public:
QuadTree* childs[4];
    bool info;
    bool parent;

QuadTree() {
    for (int i = 0; i < 4; ++i) {
         childs[i]=NULL;
    }
    info = false;
    parent = false;
}


~QuadTree() {
    for (int i = 0; i < 4; ++i) {
            delete childs[i];
    }
}
    QuadTree& operator=(const QuadTree& tree) {

    for (int i = 0; i < 4; ++i) {
        childs[i] = new QuadTree;
        if (tree.childs[i]->parent == 1) {
            childs[i] = tree.childs[i];
        }
        childs[i]->info = tree.childs[i]->info;
        childs[i]->parent = tree.childs[i]->parent;
    }
    return *this;
 }
}

所以这是添加两棵树的代码。我创建了重载运算符的下一个原因,如果一棵树的节点是白色的,另一个是父节点,我只想复制父节点。

void addTrees(const QuadTree& tree1, const QuadTree& tree2, QuadTree& end) {

if (tree1.info == 1 || tree2.info == 1) {
    end.info = 1;
    return;
}
else if (tree1.parent == 1 && tree2.parent == 1) {
    end.parent = 1;
    for (int i = 0; i < 4; ++i) {
        end.childs[i] = new QuadTree;
        addTrees(*tree1.childs[i], *tree2.childs[i], *end.childs[i]);
    }


}
else if (tree1.parent == 1) {
    end.parent = 1;
    end = tree1;

}
else if (tree2.parent == 1) {
    end.parent = 1;
    end = tree2;

}
else {
    end.info = 0;
}


}

【问题讨论】:

  • 在构造函数中,您没有在堆上分配内存。这就是为什么在调用析构函数时没有要释放的内存。
  • 也许,值得一提的是Rule of Three。通过重载复制分配,您还应该提供自定义复制构造函数。
  • 也许,值得一提的是infoparent的含义。我想知道在您的复制作业中检查孩子parents。实际上,tree 是他们的父母,您将被传递到复制作业中。那么,没有父母怎么会有孩子呢?
  • 那么 info 的意思是,节点是黑色还是白色(0 表示白色,1 表示黑色),parent 的意思是它是结束还是继续成为另一个 QuadTree。问题是我尝试添加两棵树成为一棵树,我将添加添加树的代码。

标签: c++ memory heap-memory destructor


【解决方案1】:

childs[i] = tree.childs[i]; 行没有做你认为它正在做的事情。

您现在正在引用他们分配的内存,而不再引用您分配的内存。谁试图在第二次删除这段记忆,谁就会有一个糟糕的时间。

如果您想将他们的孩子复制到您最近分配的孩子中,您将需要取消引用指针以对对象本身进行操作。 *childs[i] = *tree.childs[i]

【讨论】:

  • 恕我直言,这增加了Armin Montignys answer。虽然我想知道为什么分配处理childsinfoparent 成员而不是this 的成员。也许,我监督了一些事情......
  • 谢谢!所以我正在将 tree.childs[i] 的内存复制到 childs[i]?
  • @Ax1aL childs[i] = tree.childs[i]; 复制指针有两个(致命的)影响: 1. childs[i] 中的前一个指针丢失(如果不是nullptr,则内存泄漏)。 2. childs[i]tree.childs[i] 中的指针现在相同,稍后将在 thistree 中释放 -> 双重释放内存,这是禁止的并导致未定义行为(例如崩溃) .相反:*childs[i] = *tree.childs[i]; 将指针 tree.childs[i] 的内容复制到 *childs[i] 的内存中 -> 即再次调用该实例的复制赋值运算符。
  • 谢谢!这就是我想要的。还有一个问题,为什么它说我没有初始化“QuadTree::childs”。我让它们为空......
  • @Ax1aL 您将它们分配为空,但您没有初始化它们。初始化发生在构造函数的初始化列表中。在您的情况下,它将按原样工作,但通常首选初始化。初始化为QuadTree(): childs{ nullptr, nullptr, nullptr, nullptr }, info(false), parent(false) { }。 (如果你忽略它,编译器将使用默认初始化。)
【解决方案2】:

问题出在你的赋值运算符上。

    QuadTree& operator=(const QuadTree& tree) {

        for (int i = 0; i < 4; ++i) {
            childs[i] = new QuadTree;
            if (tree.childs[i]->parent == 1) {
                childs[i] = tree.childs[i];
            }
            childs[i]->info = tree.childs[i]->info;
            childs[i]->parent = tree.childs[i]->parent;
        }
        return *this;
    }
};

在这些行中:

if (tree.childs[i]->parent == 1) {
    childs[i]->info = tree.childs[i]->info;
            childs[i]->parent = tree.childs[i]->parent;

childs[i] 可能是 nullptr,它可以用于分配,但不能用于取消引用。

而使用-&gt;parent,您确实可以取消引用nullptr

请在解除引用前检查nullptr

【讨论】:

  • 问题是,这就是为什么我在那里添加了 if 语句,所有节点都肯定会被填满,如果它是父节点,那么肯定不会有 nullptr 用于 tree.childs[ ].
  • 是的,但是 childs[i] 本身是一个 nullptr,不能取消引用。检查,如果 childs[i] != nullptr
  • 好吧,在做任何事情之前,我会在堆上为其创建一个新内存,以防止它为 nullptr,childs[i] = new QuadTree;.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-18
  • 2019-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多