对于树结构"widget"比"shared_ptr"更好的选择?
Better option than `shared_ptr` for "widget" tree structure?
在现代C++中维护"小部件"树的最佳方法是什么?目前,我使用shared_ptr
的vector
作为子节点,并使用指向父节点的普通指针。它是这样使用的:
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>
仪式。
我还读到,您应该使用unique_ptr
,并让父元素拥有子元素。我同意一般情况,但如果你有一个"小部件"树,我不确定它会如何工作。对于"小部件"树,我指的是像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
复制,然后我在"blah"中操作了错误的按钮实例。或者它使用了一个指针,但随后它变得悬空,操作失败。我需要一个神奇的操作,将button
的所有权移动到canvas
,并用指向实际按钮的外壳对象替换button
。为此,我必须用一种伪造引用语义的智能容器来替换Element,并将真实对象隐藏在里面(我认为C++/WinRT就是这样做的)。然而,这似乎非常独特,这就是我选择shared_ptr
的原因。我还缺少其他成语吗?
您可以使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
代码更加简洁。
- C++:将控制台输出存储在宏中更好吗
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 初始化具有非默认构造函数的std::数组项的更好方法
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 为什么新的随机库比std::rand()更好
- 寻找一种更好的方法来表示无符号字符数组
- 哪种方法更好,性能明智
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 什么是更好的做法?通过指针或标识符传递类成员?
- 寻求更好地理解标准::访问
- 线程消息传递或更好:在"大师班"中访问其他班级的成员
- 有没有更好的方法来处理异常? try-catch块真的很丑
- 如何更好地检查两个 char 变量是否在一组值中?
- 有没有更好的方法对C++中的三个整数进行排序?
- 什么模板用法在阶乘中更好
- 平面缓冲区可以利用向量中的 0 吗?还是其他小波比哈尔变换更好?
- 我们应该如何使用枚举类进行索引(或者我们应该更好地避免这种情况)?
- Protobuf中重复字段的问题.使用重复字段进行序列化/反序列化的更好方法是什么?
- 比使用 s.str().c_str() 更好的表达?
- 测量时间以在 c++ 中生成更好的随机数