¿Por qué no es bueno usar herencia recursiva para implementaciones std :: tuple?

In este pregunta, Howard Hinnant dijo

Cosas implementaciones de std::tuple usan herencia recursiva. Pero los buenos no. ;-)

¿Alguien puede arrojar algo de luz sobre eso?

preguntado el 09 de marzo de 12 a las 22:03

¿tal vez tiene que ver con el envío ineficiente de argumentos? -

Probablemente sería útil si alguien pudiera delinear la diferencia entre esos buenos y algunos. -

@Cheers: creo que la inserción se ocuparía de eso, pero, de nuevo, tengo que admitir que tienen toparse con compiladores que de plano decidieron dejar de insertar a una profundidad de más de 3 o 4. -

3 Respuestas

Una implementación no recursiva tiene un mejor rendimiento en tiempo de compilación. Lo crea o no, en una biblioteca muy utilizada como std::tuple, cómo se implementa puede afectar (para bien o para mal) los tiempos de compilación que ve el cliente. Las implementaciones recursivas tienden a producir tiempos de compilación que son lineales en la profundidad de la recursividad (o pueden ser incluso peores).

Esto impacta más que solo la creación de instancias de la tupla en sí. std::get<I>(tuple) por ejemplo, tomará una cantidad lineal de tiempo de compilación para una implementación y una cantidad constante de tiempo de compilación para otra implementación. Este impacto puede deteriorarse rápidamente (o no) cuando se trata de tuplas de tuplas. Es decir, la implementación recursiva podría dar como resultado un tiempo de compilación O(N^2) mientras que la implementación no recursiva sigue siendo O(1).

Fwiw, la implementación de libc++ dispone los objetos en el orden especificado por el cliente, pero optimiza el espacio libre para los componentes vacíos utilizando la función de optimización de clase base vacía del compilador.

respondido 10 mar '12, 02:03

Esta pregunta (y su respuesta) me llevó a explorar la implementación de tupla no recursiva. Escribí una publicación al respecto: mitchnull.blogspot.com/2012/06/…. Le agradecería si pudiera dedicar un poco de tiempo para leerlo y señalar cualquier error. Gracias - mitchnull

Usé la implementación de Howards para mejorar un programa mío más pequeño. también incluí trucos de índice en las pruebas para mejorar tuple_element con respecto al tiempo de compilación y el tamaño del ejecutable. Para mi sorpresa, las cosas no mejoraron sino que empeoraron. Estoy usando gcc 4.8.2. ¿El gcc más nuevo tiene algo que optimizó la recursión de la plantilla de cabeza de cola? ¿O los trucos mencionados solo funcionan para casos de esquina? ¿Hay algún ejemplo o caso de éxito que demuestre la eficacia de las optimizaciones? - Patricio Fromberg

No recuerdo la charla GoingNative 2012 de Andrei Alexandrescu exactamente, pero habló sobre este punto, y uno de los puntos que mencionó fue el diseño de la memoria. si tengo un std::tuple<int, short, char, char>, quedará en la memoria como char, short, int y este diseño tomará (en mi sistema) 4 bytes más que si estuvieran dispuestos como int, short, char. R. Martinho Fernández me ha recordado que el el albergue mejor calificado Lo que hay que hacer sería ordenar estos en la memoria en un orden que minimice el relleno, que no es ni el orden dado ni orden inverso. (La herencia ingenua hace el orden inverso).

Si escribo std::tuple<int, char, short, char>, una tupla que funciona por herencia ingenua pondría estos en el orden char, short, int en memoria, usando 3 bytes de relleno, cuando óptimo tiene cero bytes de relleno. (Cualquiera int, short, char, char or char, char, short, int).

Suponiendo que tenga razón en que se trata de relleno, entonces R. Martinho Fernandes dicho "[mi argumento] no excluye el uso de la herencia recursiva para la implementación real en el orden óptimo", por eso especifico que ingenuo la herencia es mala.

(El orden en la memoria no no Significa que get<0> dará un objeto diferente, y R. Martinho Fernandes señala correctamente que el pedido debe ser invisible para el usuario. Sin embargo, estos fueron los puntos que me recordaron del evento GoingNative).

El video esta en http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic y las diapositivas están en http://ecn.channel9.msdn.com/events/GoingNative12/GN12VariadicTemplatesAreFunadic.pdf.

Respondido el 18 de enero de 21 a las 12:01

¿Dónde habla de algo más en su comentario? - Johannes Schaub - litb

Si una tupla está lo suficientemente "anidada profundamente" como para sobrecargar al compilador, es posible que desee ver su código nuevamente. No creo que haya una manera de hacerlo sin mensajes de error difíciles. - Pato morando

ah, entonces no es la herencia recursiva lo que es malo, sino ingenuo herencia recursiva? Me pregunto si @Howard estaba en otra cosa y tiene otro punto a favor de otra técnica. - Johannes Schaub - litb

@MooingDuck: si tienes tuplas tan profundamente anidadas, diría que el pasado lo que quieres hacer es mirar tu código de nuevo... ;) - jalf

@MooingDuck Oye, escribí una implementación muy cruda de una tupla que siempre te brinda el diseño óptimo: ideone.com/Z5hfo. Calcula el orden óptimo (#ifdefed para las implementaciones de libc++ y libstdc++) y envuelve una tupla de la biblioteca estándar para ocultar el orden real al usuario. Todavía no puedo obtener todos los get<> llama para compilar en GCC, pero todos los static_asserts están pasando, y funciona bien en clang con libc++. No tengo idea de cómo hacer un análisis de rendimiento en tiempo de compilación, por lo que es posible que esto sea ineficiente. Hazme un ping en el chat si tienes alguna pregunta :) - R. Martinho Fernández

Una razón para no usar una cadena de clases base es que no hay una cadena de constructores involucrados: los argumentos se reenvían directamente al subobjeto apropiado. Además, parece que una implementación no recursiva ejerce mucha menos presión sobre el compilador y crea muchos menos símbolos [internos]. Sin mencionar que en realidad es más fácil no a una cadena de clases base.

respondido 09 mar '12, 23:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.