【发布时间】:2016-08-31 09:45:48
【问题描述】:
上下文:
通常会出现我需要聚合的情况:一个对象使用另一个对象而不拥有它。也就是说,一些主模块会为其他人创建和共享一个对象。
但是,到目前为止,我还没有找到正确的实现方法。
以往的研究:
1) 类 C 指针: 共享对象作为指针提供。问题是要由程序员正确管理创建、共享和删除的顺序,很容易携带悬空指针。
int main()
{
A a;
B b(&a);
return 0;
}
2) 弱指针: 使用共享/弱指针解决了悬空指针的问题。主要问题是:它避免使用堆栈对象。它还转发异常情况,在最好的情况下是一个有争议的话题,在最坏的情况下是不可能的(内核/低级代码)。
int main()
{
std::shared_ptr<A> a(new A());
std::weak_ptr<A> wa = a; // optional, but required to show the weak_ptr use
B b(wa);
}
3) 共享指针: 仅使用共享指针与(2)有同样的问题,但另外 A 的所有权是未知的:这违反了几个设计准则。
4) 对象引用: 共享对对象的引用解决了悬空问题,并且可能是最简单的解决方案。另一方面,它强制聚合对象在构造函数中传递,它避免了赋值运算符,并且总体上限制了设计。
int main()
{
A a;
B( a );
}
5) 永远不要聚合,只是作为参数传递。 即使可能,这也会极大地增加某些函数的参数数量。在我看来,这太复杂了。
6) 单例模式 Singleton 允许从多个模块访问单个对象。但是,这只允许共享一个实例,并且违反了几条设计准则。
问题:
在现代 C++ 中实现聚合的正确方法是什么?
理想的目标是:
- 使代码易于维护,避免错误。
- 灵活地以不同方式使用它(例如堆栈/堆)
- 没有太多额外的复杂性或晦涩的代码。
【问题讨论】:
-
我认为这里没有足够的信息来回答这个问题。它取决于比您共享的更多的架构考虑因素。这些都是有效的选项,具体取决于其他内容,但在“现代”c++ 中,如果可能,您不希望使用原始指针(而且在大多数情况下也不需要使用
new) -
没有一个真正的答案。选择最佳设计来解决您的特定问题。
-
为什么B不拥有A?您是否有自定义垃圾收集器来回收堆? B 比 A 活吗?
-
原始指针被模块传递和持有并没有错,这些模块通过它们的语义知道它们不拥有并且永远不会拥有它们传递的对象它们传递的对象的生命周期超过了它们自己的生命周期。在许多用例中,这是众所周知的,尤其是。关于建模聚合。如果不正确,则使用 shared_ptr 或weak_ptr,具体取决于您是否要延长聚合对象的生命周期。顺便说一句,w.r.t。 #5,共享参考不解决悬空问题。
-
@davidbak 存在的问题是所有权从类型上不清楚。因此,
non_owning_ptr<T>(世界上最愚蠢的智能指针)的提议使得所有权的缺乏变得清晰。
标签: c++ c++11 aggregation