为什么对std :: tuple实现使用递归继承不好?

时间:2012-03-09 22:11:52

标签: c++ c++11 stdtuple

this问题中,Howard Hinnant说

  

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

有人可以对此有所了解吗?

3 个答案:

答案 0 :(得分:30)

A non-recursive implementation具有更好的编译时性能。信不信由你,在像std::tuple这样频繁使用的图书馆工具中,它的实现方式会影响(无论好坏)客户看到的编译时间。递归实现往往会产生在递归深度上呈线性的编译时间(或者可能更糟)。

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

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

答案 1 :(得分:3)

我不记得Andrei Alexandrescu的GoingNative 2012演讲完全,但他谈到了这一点,他提到的一点是内存布局。如果我有一个std::tuple<int, short, char, char>,它将作为char, short, int存储在内存中,并且这个布局将比在int, short, char布局时(在我的系统上)多4个字节。 R. Martinho Fernandes已经提醒我,最好要做的事情就是按照最小化填充的顺序在内存中对它们进行排序,这既不是也不是反向的顺序订购。 (天真的继承确实颠倒了顺序)。

如果我写std::tuple<int, char, short, char>,那么通过朴素继承工作的元组将使用3个字节的填充将这些以char, short, int的顺序放在内存中,当最优时具有零字节的填充。 (int, short, char, charchar, char, short, int)。

假设我是正确的,它是关于填充的,那么R. Martinho Fernandes said“[我的论点]并不排除在最佳顺序中实际实现使用递归继承。”,所以这就是为什么我指定naïve继承是坏的。

(内存中的顺序意味着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

答案 2 :(得分:2)

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