2017-08-23 86 views
1

我在GUI中有一个窗口系统,我不确定销毁顺序。每个窗口都有一个矢量持有其子女,各自也都有一个指向它的父:删除父/子窗口层次结构的最佳方法

auto root = new Window; 
root->addChild(new Window); 
root->addChild(new Window); 
auto child = root->addChild(new Window); // Return value is the newly created Window 
child->addChild(new Window); 
child->addChild(new Window); 
auto grandchild = child->addChild(new Window); 
grandchild->addChild(new Window); 
grandchild->addChild(new Window); 
grandchild->addChild(new Window); 

//我要删除的子指针,首先我需要从其父的孩子矢量抹去它的指针。

child->parent->children.erase(child->parent->children.begin() + child->positionInParentsVector - 1); 

child->destroy(); 

void Window::destroy() 
{ 
    if (children.size() == 0) delete this; 
    else for (auto i : children) i->destroy(); 
} 

或与智能指针的载体,那会是足够做:

// Remove reference of child from parent's children vector, then 

delete child; 

我已阅读,它是确定确实删除了这一点。这很难让我的头脑。

+0

智能指针很可能是最好的所以它是所有自动清理。 但是,如果您的层次结构非常深,您可能会在析构函数中发生堆栈溢出。在这种情况下,您将需要像发布一样“手动”释放所有内容。 –

+0

另外,由于destroy函数是递归的,我只需要在最高级别删除父项的引用,这意味着我需要创建一个函数来删除引用,另一个函数执行递归删除,对吧?这可能是三个函数,一个removeReferenceAndDestroy,并在那个removeReference中,然后执行递归destroy()。没有更优雅的方式? – Zebrafish

+0

如果堆栈溢出*是一个现实的问题(它也会发生在常规层次递归遍历中),那么它实际上*不是*就像你显示的那样,你需要不经过递归而是使用循环。 –

回答

1

我认为你有点困惑自己。以下自包含例如不具有内存泄漏:

#include <utility> 
#include <vector> 
#include <memory> 

using std::vector; 
using std::unique_ptr; 

struct Window { 
    Window() = default; 
    vector<unique_ptr<Window>> children; 
    Window* parent = nullptr; 
    ~Window(); 

    Window* addChild(std::unique_ptr<Window> c) { 
     c->parent = this; 
     children.push_back(std::move(c)); 
     return children.back().get(); 
    } 
}; 

Window::~Window() = default; 

int main() { 
    auto root = std::make_unique<Window>(); 
    root->addChild(std::make_unique<Window>()); 
    auto child = root->addChild(std::make_unique<Window>()); 
    child->addChild(std::make_unique<Window>()); 
}; 

类不能包含本身,但它可以包含一个unique_ptr到其自身(或容器体)。在这个方案中,所有的递归破坏都是正确且自动地发生的。你可以用各种方式打扮,但这是基本的想法。

这里还有其他一些关于良好的对象和类设计和封装的问题,但那是另一个问题。注意:在绝大多数情况下,您不应该使用称为destroy的方法,但应该在析构函数中进行。

除非您编写相对较低级别的代码(如您自己的内存分配器),否则基本上不需要在C++ 11或更高版本中编写新的或删除。

活生生的例子:http://coliru.stacked-crooked.com/a/adef8cc40de4916a

+0

谢谢。有趣的是,大多数人倾向于远离原始指针,以及C++的发展趋势如何。我想这对于自动清理是一件好事,绝对容易得多。智能指针向量总是一个额外的电话,对吧?在销毁vector之后,每个unique_pointer的析构函数被调用,然后调用指向对象的delete。 – Zebrafish

+0

@斑马鱼你必须小心。人们远离*拥有*原始指针。我的代码包含原始指针成员变量(通常是一件坏事,但有时候你需要它)和一个从成员变量返回的指针。但是,在这两种情况下,它都是非所有关系。请注意,在'addChild'中,最好检查'c'实际上是否拥有'Window',如果不是,则抛出。然后你可以返回一个'Window&',它更好,因为它不能为空(如果你好奇,我可以改变代码)。 –

+0

@斑马鱼一个额外的电话,相对​​于什么?您的描述是正确的,但我不明白如果使用手动而不是自动清理进行编码,速度会更快。 –

相关问题