virtuales que puro puras polimorfismo objeto modificador herencia funciones entre ejercicios diferencia c++ linker compiler-optimization vtable dead-code

puro - Funciones virtuales de C++: ¿Puede el enlazador eliminar entradas en la tabla de funciones virtuales que no se llaman?



polimorfismo puro c++ (1)

Esta pregunta es una especie de seguimiento para eliminar las funciones virtuales no utilizadas , que no son suficientemente profundas para mi interés.

El problema: al definir clases que tienen funciones virtuales, el compilador asigna almacenamiento para la tabla de funciones virtuales y almacena punteros a las funciones de la tabla. Esto hace que el vinculador mantenga el código de esas funciones, independientemente de si alguna vez se las llama. Esto podría provocar que se retenga una gran cantidad de código muerto en el ejecutable, incluso cuando la configuración de optimización del compilador exija la eliminación del código muerto.

Ahora, si en ninguna parte del ejecutable hay una llamada de una función virtual particular (o, en otras palabras, un acceso a la ranura respectiva de la tabla de funciones virtuales), el puntero de función correspondiente podría omitirse de la tabla de funciones virtuales, y el enlazador eliminaría el código de la función, con posibles omisiones adicionales de otro código que no se refiera a referencia.

Obviamente, esto no puede ser hecho por el compilador, ya que solo queda claro en el tiempo del enlace si se llama a una función virtual particular (suponiendo que haya un enlace estático; está claro que no se puede hacer con un enlace dinámico). No estoy lo suficientemente familiarizado con los vinculadores para saber si el compilador puede emitir tablas de funciones virtuales de tal manera que el vinculador pueda eludir selectivamente entradas individuales no utilizadas en la tabla.

Básicamente, mi línea de pensamiento es la siguiente: Un puntero de función en una tabla de funciones virtuales es una referencia a una función que el enlazador usa para determinar que el código de la función necesita ser retenido en el ejecutable. De manera similar, una llamada de función virtual es una referencia a una ranura particular en todas las tablas de funciones virtuales que se derivan de la clase a la que se llama la función virtual. ¿Podría este tipo de referencia ser comunicada al enlazador de tal manera que pueda eludir una ranura de tabla de función virtual cuando no hay referencias a ella?

Tenga en cuenta que esto no es lo mismo que reemplazar una llamada de función virtual con una llamada directa cuando el compilador puede determinar el destino de la llamada en tiempo de compilación. Sé que algunos compiladores pueden hacer eso, pero ese es un caso diferente porque en realidad se llama a la función, y es la sobrecarga del envío de funciones virtuales la que se elimina. En mi caso, quiero que se elimine todo el código de las funciones que no se llaman.

Si tuviera control sobre todas las definiciones de clase, podría eliminar manualmente todas las funciones virtuales que no son llamadas. Pero eso no es realista cuando se usan bibliotecas.

¿Es esto algo que se puede hacer con "optimización de tiempo de enlace" o "optimización de todo el programa"? ¿Hay compiladores que hacen eso con éxito?


El problema con el código inactivo es que el compilador no puede estar seguro de que el código está muerto desde la perspectiva de las bibliotecas dinámicas. Un ejecutable puede incluir dinámicamente una biblioteca que usa el código muerto (deriva de las clases propietarias del código inactivo).

Además de eso, cambiar la estructura de la tabla v durante el tiempo de enlace podría funcionar perfectamente bien si el ejecutable es el único que hace llamadas a funciones. Sin embargo, si una biblioteca dinámica realiza alguna llamada, tendrá una comprensión diferente de la tabla v y llamará a la función incorrecta.

Debido a estos hechos, y en el valor nominal no se gana mucho (si es que se tiene) el rendimiento, es muy poco probable que los vinculadores optimizadores tengan esta característica.

La desvirtualización de las funciones virtuales está realmente relacionada con esto, y los enlazadores de optimización segura solo pueden descentralizar un número muy pequeño de llamadas a funciones. Por ejemplo, solo puede descentralizar la función si puede garantizar que ninguna biblioteca dinámica pueda reproducir ninguna parte en la pila de llamadas.

edit @curiousguy ha planteado un caso en el que el compilador puede ser un poco más liberal con la optimización, y es entonces cuando el enlazador puede saber que ningún código externo conoce la clase. Un ejemplo de esto es una clase con alcance de archivo.