汇总多个捐助者的捐款

时间:2009-05-08 11:49:29

标签: c++ generics stl

当我尝试使我的C ++技能现代化时,我一直遇到这种情况,“STL方式”对我来说并不明显。

我有一个对象想要将多个来源的贡献收集到一个容器中(通常是std::vector)。每个源都是一个对象,每个对象都提供一个方法get_contributions(),它返回任意数量的贡献(从0到多个)。收集者将在每个贡献者上调用get_contributions()并将结果聚合到一个集合中。

问题是,get_contributions()的最佳签名是什么?

选项1:std::vector<contribution> get_contributions() const

这是最直接的,但由于收集器将每组结果复制到主集合中,因此会导致大量复制。是的,性能在这里很重要。例如,如果贡献者是几何模型并且获得贡献等于将它们分解为三角形以进行渲染,那么速度将被计算并且贡献的数量可能是巨大的。

选项2:template <typename container> void get_contributions(container &target) const

这允许每个贡献者通过调用target.push_back(foo)将其贡献直接添加到主容器中。这里的缺点是我们将容器暴露在其他类型的检查和操作中。我宁愿保持界面尽可能窄。

选项3:template <typename out_it> void get_contributions(out_it &it) const

在此解决方案中,聚合器将为主集合传递std::back_insert_iterator,并且各个贡献者将为每个贡献执行*it++ = foo;。这是迄今为止我提出的最好的,但我仍然觉得必须有更优雅的方式。 back_insert_iterator感觉就像一块垃圾。

选项3是最好的,还是有更好的方法?这种聚会模式有名字吗?

3 个答案:

答案 0 :(得分:2)

还有第四个,需要您定义迭代器范围。查看Alexandrescu关于"Iterators must go"的演讲。

答案 1 :(得分:1)

选项3是最惯用的方式。请注意,您不必使用back_insert_iterator。如果您知道要添加多少元素,则可以调整向量的大小,然后提供常规向量迭代器。它不会调用push_back(并且可能会省去一些复制)

back_insert_iterator的主要优点是它可以根据需要扩展矢量。

虽然这不是一个蠢货。它是为这个目的而设计的。

一个小的调整是按值传递迭代器,然后在函数返回时返回它。

答案 2 :(得分:0)

我想说有两种惯用的STL方式:你的选项3(采用输出迭代器,顺便通过值传递)并使用一个函数来调用每个贡献。

当然,如果适合将get_contributions实现为模板,则每个都适用。