23

这个问题上,Howard Hinnant 说

std::tuple 的一些实现使用递归继承。但好人没有。;-)

有人可以解释一下吗?

4

3 回答 3

32

非递归实现具有更好的编译时性能。信不信由你,在一个使用量很大的库设施中,如std::tuple,它的实现方式会影响(无论好坏)客户端看到的编译时间。递归实现倾向于产生在递归深度上是线性的编译时间(或者可能更糟)。

这不仅仅影响元组本身的实例化。 std::get<I>(tuple)例如,一个实现将花费线性量的编译时间,而另一个实现将花费恒定量的编译时间。在处理元组的元组时,这种影响可能会迅速恶化(或不会恶化)。即递归实现可能会导致 O(N^2) 编译时间,而非递归实现仍然是 O(1)。

Fwiw,libc++ 实现按客户端指定的顺序排列对象,但使用编译器的空基类优化工具优化空组件的空间。

于 2012-03-10T02:39:59.320 回答
3

我不记得 Andrei Alexandrescu 的 GoingNative 2012 演讲的确切内容,但他谈到了这一点,他提到的要点之一是内存布局。如果我有std::tuple<int, short, char, char>,它将在内存中 aschar, short, int并且此布局将(在我的系统上)比布局为 4 个字节多int, short, charR. Martinho Fernandes提醒我,最好的办法是以最小化填充的顺序在内存中排序这些,既不是给定的顺序,也不是相反的顺序。(朴素的继承确实是逆序的)。

如果我写std::tuple<int, char, short, char>,一个通过朴素继承工作的元组会将它们按顺序排列char, short, int在内存中,使用 3 个字节的填充,当最佳具有零字节的填充时。(int, short, char, charchar, char, short, int)。

假设我是对的,它是关于填充的,然后 R. Martinho Fernandes“[我的论点] 并不排除以最佳顺序在实际实现中使用递归继承。”,这就是我指定天真的继承的原因不好。

(内存中的顺序并不意味着get<0>会给出不同的对象,并且 R. Martinho Fernandes 正确地指出该顺序应该对用户不可见。但是,这些是我从 GoingNative 事件中得到的提醒。)

视频位于http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic,幻灯片位于http://ecn.channel9.msdn.com/events/GoingNative12/ GN12VariadicTemplatesAreFunadic.pdf

于 2012-03-09T22:13:25.877 回答
2

不使用基类链的一个原因是不涉及构造函数链:参数直接转发给适当的子对象。此外,似乎非递归实现对编译器的压力要小得多,并且创建的 [内部] 符号也少得多。更不用说使用基类链实际上更容易。

于 2012-03-09T23:07:36.510 回答