2011-07-01 10 views
9

Digamos que tengo dos archivos .cpp, archivo1.cpp y archivo2.cpp, que usan std::vector<int>. Supongamos que file1.cpp tiene un int main(void). Si compilé ambos en file1.o y file2.o, y vinculé los dos archivos de objeto en un binario de duende que puedo ejecutar. Estoy compilando en una máquina Ubuntu Linux de 32 bits.Archivos de objeto en C++ con plantilla

Mi pregunta se refiere a cómo el compilador y el enlazador juntos los símbolos para el std :: vector:

  • Cuando el enlazador hace que mi binario final, ¿hay duplicación de código? ¿El enlazador tiene un conjunto de código "con plantilla" para el código en f1.o que usa std::vector y otro conjunto de código std::vector para el código que comprende f2.o?

yo probamos este para mí (he usado g++ -g) y miré el desmontaje ejecutable final, y me encontré con las etiquetas generadas por el constructor de vectores y otros métodos eran aparentemente al azar, aunque el código de f1.o apareció haber llamado al mismo constructor que el código de f2.o. Sin embargo, no podría estar seguro.

Si el enlazador previene la duplicación del código, ¿cómo lo hace? ¿Debe "saber" qué plantillas son? ¿Siempre previene la duplicación de código con respecto a múltiples usos del mismo código de plantilla en múltiples archivos de objeto?

Respuesta

8

Sabe cuáles son las plantillas a través de name mangling. El tipo de objeto está codificado por el compilador en su nombre, y eso le permite al vinculador filtrar las implementaciones duplicadas de la misma plantilla.

Esto se hace durante la vinculación, y no en la compilación, porque cada archivo .o se puede vincular con cualquier cosa, por lo que no se puede despojar de algo que luego puede ser necesario. Solo el enlazador puede decidir qué código no se usa, qué plantilla está duplicada, etc. Esto se hace usando "Weak Symbols" en la lista de símbolos del objeto: Símbolos que el enlazador puede eliminar si aparecen varias veces (en lugar de otros símbolos, como funciones definidas por el usuario, que no pueden eliminarse si están duplicadas y causar un error de enlace).

+0

Esto no se refiere a la mayor parte de la pregunta de la OP. Es cierto, pero no es particularmente relevante para lo que se pregunta aquí. – templatetypedef

+0

@templatetypedef - Me permito diferir. * Si el enlazador impide la duplicación del código, ¿cómo lo hace? ¿Debe "saber" qué plantillas son? * El enlazador sabe a través del cambio de nombre. Código en línea: está duplicado, el vinculador no tiene nada que ver con eso. – littleadv

+0

@ littleadv- Tiene toda la razón, pero su respuesta no explica por qué el enlazador utiliza el nombre de manipulación, cómo los nombres destrozados para las funciones de plantilla difieren de las funciones normales, cómo el vinculador decide qué versiones elegir, etc.No estoy tratando de decir que esto es fuera de tema o incorrecto, sino que a menos que ya supiera la respuesta a la pregunta, no creo que esta respuesta sea útil. – templatetypedef

0

Técnicamente, debido a la "regla de una definición", solo hay un std::vector<int> y, por lo tanto, el código debe vincularse entre sí. Lo que puede suceder es que algún código esté en línea, lo que aceleraría el tiempo de ejecución pero podría producir más código.

Si tenía un archivo usando std::vector<int> y otro usando std::vector<unsigned int>, entonces tendría 2 clases y potencialmente un montón de código duplicado.

Por supuesto, los escritores de vector pueden usar algún código común para ciertas situaciones, por ejemplo, tipos de POD que eliminan la duplicación.

+0

No me preocupa duplicar std :: vector y std :: vector . ¿Cuál es exactamente la "regla de una definición"? ¿La definición de std :: vector no está creada en tiempo de compilación para f1.o y f2.o? – Chris

+0

la "Regla de una sola definición" es por archivo de objeto, entre archivos de objeto separados obtendrá dos instancias diferentes del vector si ambos la usan. Lo que está en línea - será duplicado, lo que no - manejado por el enlazador. – littleadv

+0

En resumen, la regla de una definición establece que si aparecen instancias de plantillas idénticas en más de una unidad de compilación, eso solo cuenta para el compilador como una sola definición para esa instancia de plantilla. Básicamente, C++ tiene este paso adicional entre la compilación y el enlace de código objeto con el propósito específico de eliminar estas copias adicionales del código de la plantilla. – SingleNegationElimination

Cuestiones relacionadas