对于"小部件"比'shared_ptr`更好的选择树结构?

时间:2017-11-18 12:41:45

标签: c++

维护"小部件"树的最佳方法是什么?在现代C ++中?目前,我使用vector shared_ptr作为子节点,并使用指向父节点的普通指针。它的使用方式如下:

auto canvas = make_shared<Element>("canvas");
auto button = make_shared<Element>("button");
canvas->addChild(button);
// do something with either canvas or button

我最满意,但我不喜欢make_shared<Element>仪式。

我还读到你should use unique_ptr并让父元素拥有子元素。我同意一般情况,但如果你有一个&#34;小部件&#34;我不确定这是怎么回事。使用&#34;小部件&#34;树,我指的是像你一样的树。 GUI代码。它是通过在这里和那里添加节点手动构建的,而外部代码经常需要访问各个节点。如果我使用unique_ptr,则对addChild的调用将移动指针,上述代码将无法再使用子对象。我可以让addChild再次返回常规指针,但这会使调用网站更复杂。

理想情况下,我只能说:

Element blah() {
    // this could also be changed to Element* or some_pointer<Element>,
    // but I want the call site to be clean and simple and not leak
    // implementation details
    Element canvas("canvas");
    Element button("button");
    canvas.addChild(button);
    button.manipulate();
    return canvas;
}

auto canvas = blah();
canvas.children[0].manipulate();

但当然这在C ++中不起作用。要么addChild复制,要么我操纵错误的按钮实例&#34; blah&#34;。或者它需要一个指针,但随后它变得悬空并且操作失败。我需要一个神奇的操作,将button的所有权移至canvas,并用指向真实按钮的外壳对象替换button。为此,我必须用一种伪造引用语义的智能容器替换Element,并隐藏真实对象(我认为C ++ / WinRT就是这样做的)。然而,这似乎非常单一,这就是为什么我选择shared_ptr。我还缺少其他成语吗?

1 个答案:

答案 0 :(得分:1)

您可以使addChild的行为类似于emplace方法,并让它在内部创建unique_ptr,然后返回非拥有指针(或引用)。即类似的东西:

template <class... Args>
Element & Element::addChild (Args && ... args) {
  children_.push_back(std::make_unique<Element>(std::forward<Args>(args)...));
  return children_.back();
}

所以现在你可以在不暴露呼叫站点的任何指针内容的情况下执行以下操作:

Element blah () {
  Element canvas("canvas");
  Element & button = canvas.addChild("button");
  button.manipulate();
  return canvas;
}

修改:使示例addChild代码更简洁。