2010-11-25 7 views
9

leí este article de D. Kalev esta mañana acerca de la nueva característica de C++ 11 "incumplido y funciones eliminados", y no se puede entender la parte sobre el rendimiento, a saber:¿Por qué el constructor generado implícitamente (et al.) Sería más eficiente que uno definido por el usuario (trivial)?

la definición manual de una la función de miembro especial (incluso si es trivial) suele ser menos eficiente que una función implícitamente definida.

buscando en Google para encontrar una respuesta, he encontrado otra article del mismo autor:

el constructor sintetizado y constructor de copia de permitir la aplicación para crear código que es más eficiente que el código escrito por el usuario, ya puede aplicar optimizaciones que de otro modo no siempre son posibles.

No hay explicación, pero leo periódicamente afirmaciones similares.

Pero ¿cómo es que la escritura:

class C { C() = default; }; 

puede ser más eficiente que

class C { C(){} }; 

? Pensé que un compilador sería lo suficientemente inteligente como para detectar esa situación y optimizarla. En otras palabras, ¿cómo es más fácil para el compilador optimizar cuando ve =default en lugar de {} (función de cuerpo vacío)?

Editar: la pregunta se editó para agregar la etiqueta "C++ 11", pero esta pregunta permanece en el contexto C++ 03: simplemente reemplace class C {C()=default;}; por class C {};, por lo que realmente no es una pregunta específica de C++ 11.

+0

Buena pregunta. También creo que cualquier compilador que no optimice esto está defectuoso. Veamos si alguien puede dar una buena razón por la que eso no es posible. –

+2

Pruebe con un compilador de C++ 1x para generar el ensamblado. Esto responderá a tu pregunta definitivamente. Dudo que haya alguna diferencia, ya que como dices, el compilador es lo suficientemente inteligente. Los comentarios como el que citó son malos, en mi opinión, porque hace que los desarrolladores de C++ piensen demasiado sobre el rendimiento. El 99% del tiempo hay otras cualidades de las que preocuparse antes incluso de considerar tontas optimizaciones de micro rendimiento. –

+0

@Daniel: gracias, pero no sé nada sobre el ensamblaje, y no estoy interesado en obtener micro-rendimiento ... Pero estoy interesado en saber * por qué * habría alguna ganancia, ya sea micro. – rafak

Respuesta

0

Para ser sincero, tampoco puedo verlo.

Entre otras cosas, puedo ver por qué hay que utilizar

class C { C() = default; }; 

que me parece el mismo que

class C { }; 

O, si se proporcionan otros constructores, como:

class C { 
    C() {} 
    // other constructors. 
}; 

No veo el problema real el autor está escrito acerca de aquí.

+0

Me gusta el comentario de Daniel Lidström bajo la pregunta aquí. Creo que apunta a qué problema irreal está escribiendo el autor. –

+0

Los dos primeros SON iguales, el constructor predeterminado está predeterminado, de forma explícita o implícita no hace ninguna diferencia. "Si se proporcionan otros constructores" es ** exactamente ** el razonamiento para la nueva sintaxis '= default', ya que permite crear una clase * trivially-copyable * con conversiones definidas por el usuario. El constructor con un cuerpo vacío es suficiente para hacer que la clase * no se pueda copiar trivialmente *. –

+0

@Ben ok, pero me parece que el objetivo del artículo era la capacidad, por parte del compilador, de generar un binario más optimizado con la sintaxis '= default'. – Simone

7

Usted pregunta, ¿cómo es que

class C { C() = default; }; 

puede ser más eficiente que

class C { C(){} }; 

Bueno, ambos constructores no hacen nada, por lo que no tiene sentido hablar de la eficiencia de ese ejemplo.

Pero más generalmente, en p.un constructor de copia uno puede imaginar que copiar un elemento POD a la vez no será reconocido como optimizable por un optimizador simple, mientras que con la generación automática podría hacer un memcpy. Quién sabe. Es un problema de Calidad de Implementación, y también puedo imaginarme fácilmente el frente a.

Por lo tanto, mida, si es importante.

Saludos & HTH.,

+1

+1 para consejos de medición. :) –

+0

Estoy totalmente de acuerdo, pero Kalev da casi el mismo ejemplo (un destructor predeterminado virtual de hecho), y dice (citado en la publicación): "incluso si es trivial", de ahí mi pregunta. Pero nunca voy a medir eso, quería entender las verdaderas razones, no dadas por el autor. – rafak

+0

No es verdad que ambos casos no hagan nada, ambos inicializan todos los miembros de la clase usando sus constructores por defecto (si no son primitivos) – Motti

1

demandas de rendimiento tomar "con un grano de sal".

He oído a un profesor de MIT de alta calificación hacer un reclamo así por su cosa favorita, y la única razón por la que nadie le preguntó "por qué" fue porque era un profesor de MIT de alta calificación.

Tales constructores y destructores pueden tener otras ventajas, pero las afirmaciones sobre el rendimiento (fuera de la gran O) casi nunca son significativas, excepto en circunstancias altamente artificiales.

2

No tiene sentido hablar de "definición manual de una función de miembro especial (incluso si es trivial)", porque las funciones de miembro especiales proporcionadas por el usuario son, por definición, no triviales. Esta no trivialidad entra en juego cuando se usan rasgos de tipo, y también POD-ness, y muchas optimizaciones solo son posibles con tipos triviales o POD.

Una mejor reafirmación de la misma cita sería:

Las funciones miembro especiales en default permiten bibliotecas de detectar que las llamadas a estas funciones pueden omitirse por completo.

Desde sección de 12,1 [class.ctor]

Un constructor por defecto es trivial si no es ni ni borrado y proporcionado usuario si:

  • su clase no tiene funciones virtuales (10.3) y sin base virtual clases (10.1) y
  • ningún miembro de datos no estática de su clase tiene un aparato ortopédico o igual-inicializador y
  • todas las clases base directos de su clase tener constructores por defecto triviales, y
  • para toda la no- los miembros de datos estáticos de su clase que son del tipo de clase (o una matriz de los mismos), cada clase tiene un constructor predeterminado trivial.

De lo contrario, el constructor predeterminado es no trivial.

De la sección 12.8 [class.copy]:

Una copia/constructor movimiento para la clase X es trivial si no es ni ni borrada y proporcionado por el usuario si

  • clase X no tiene funciones virtuales (10.3) y no clases base virtuales (10.1) y
  • el constructor seleccionado para copiar/mover cada subobjeto directo de clase base es trivial, y
  • para cada miembro de datos no estático de X que es de tipo de clase (o serie de los mismos), el constructor seleccionado para copiar/mover ese miembro se trivial;

de lo contrario la copia/mover constructor es no trivial.

de la sección 9, [class]:

A trivialmente copiable clase es una clase que:

  • no tiene no triviales de copia constructores (12.8),
  • no tiene constructores de movimientos no triviales (12.8),
  • no tiene de asignación de copia no trivial operadores (13.5.3, 12.8),
  • tiene no hay operadores de asignación movimiento no triviales (13.5.3, 12.8), y
  • tiene un trivial destructor (12.4).

A clase trivial es una clase que tiene una trivial constructor predeterminado (12.1) y es trivialmente copiable. [Nota: en el modelo en particular, una clase trivial o trivialmente copiable no tiene funciones virtuales o clases base virtuales. - nota final]

Cuestiones relacionadas