【发布时间】:2014-09-01 13:14:21
【问题描述】:
在过去的几周里,我一遍又一遍地遇到同样的问题。归结为它的核心,我构建了一个(有向无环)对象层次结构,例如:
a -> cb -> cb -> d
一个实例可以有多个父级和多个子级。 c 可能是读者和作者之间共享的值。 b 可能是一个复合值。层次结构很容易由工厂创建 - 例如。 a.setChild(new C())。后来,客户只关心根,她调用getValue() 或setValue()。
我的问题是:谁来清理层次结构?谁负责在b 或c 上致电delete?
选项 - 工厂创建节点,工厂必须删除节点: 我不喜欢这个选项,因为我理解工厂是
new的替代品。在它创建的实例被销毁之前保留一个工厂感觉很奇怪。选项 - “智能”指针: 不太好,因为它污染了接口,并且为指针之类的简单事物引入了很多复杂性。
选项 - 执行内存管理的类似图形的类: 该类收集所有节点
a、b、c、d,...并提供对根的访问。节点本身相互引用,但不删除子节点或父节点。如果“图”或复合管理器被销毁,它会销毁所有节点。
我更喜欢最后一个选项。然而,它使层次结构的构建复杂化。要么在外部构建层次结构,然后将每个节点告诉图形,要么在图形内部构建层次结构,这闻起来像选项 1。图形只能删除它知道的内容。因此,如果您必须将节点传递给图形,内存泄漏就在某种程度上存在于设计中。
这个问题有模式吗?你更喜欢哪种策略?
编辑 1 - 2014 年 9 月 1 日:抱歉,对于智能指针不具体。我试图避免另一个“何时使用智能指针问题”,而是将问题集中在替代解决方案上。但是,如果智能指针确实是最佳选择(或必要时),我愿意使用它们。
在我看来,签名 setChild(C* child) 应该优先于 setChild(std::shared_ptr<C> child),原因与 for-each 循环应该优先于迭代器相同。但是,我必须承认,像 std:string 一样,共享指针的语义更具体。
就复杂性而言,节点内的每个操作现在都必须处理共享指针。 std::vector<C*> 变为 std::vector< std::shared_ptr<C> >, ... 此外,每个指针都携带一个引用计数,如果有其他选择,则可以避免这种情况。
我应该补充一点,我开发了一个实时系统的低级部分。它不是固件,而是关闭。
编辑 2 - 2014 年 9 月 1 日: 感谢您的所有意见。我的具体问题是:我得到一个字节数组,可以说传感器数据。在某些时候,我被告知哪个值被写入该数组的哪个位置。一方面,我想要从数组中的某个位置映射到原始值(int32,double,...)。另一方面,我想将原始值合并到复杂类型(结构、向量等)。不幸的是,并非所有映射都是双向的。例如。我可以读取值之间的比较,但我无法根据比较结果写入值。因此,我将读取器和写入器分开,并让他们在必要时访问相同的值。
【问题讨论】:
-
为什么智能指针会污染接口并引入复杂性??
-
"它污染了界面" 举个例子。
-
如果“客户端只关心根”,那么无论您是否认为这种暴露是“污染”,智能指针都不会暴露在界面中。还是您指的是用于构建图形的界面?在这种情况下,我认为智能指针与污染完全相反,因为它们明确指定了所有权模型。
-
如果父母应该拥有孩子,则不应首选
parent.setChild(C* child)。首选 shared_ptr 或 unique_ptr。 -
a、b、c和d的生命周期是多少?他们是独立的吗?或者他们会同时死去?
标签: c++ memory-management graph factory composite