¿Es RVO (optimización del valor de retorno) en objetos no identificados un comportamiento universalmente garantizado?

StackOverflow https://stackoverflow.com/questions/8410877

Pregunta

Esta pregunta está en un aspecto diferente (también limitado a GCC). Mi pregunta es solo para objetos sin nombre. Optimización del valor de retorno se le permite cambiar el comportamiento observable del programa resultante. Esto parece ser mencionado en Standard también.

Sin embargo, esto "permitido" El término es confuso. ¿Significa que RVO Está garantizado suceder en cada compilador. Debido a la RVO a continuación, el código cambia su comportamiento observable:

#include<iostream>
int global = 0;
struct A {
  A(int *p) {}
  A(const A &obj) { ++ global; }
};

A foo () {  return A(0); }  // <--- RVO happens
int main () {
  A obj = foo(); 
  std::cout<<"global = "<<global<<"\n"; // prints 0 instead of 2
}

¿Se supone que este programa imprime global = 0 Para todas las implementaciones, independientemente de las optimizaciones del compilador y el tamaño del método de foo ?

¿Fue útil?

Solución

Según el estándar, el programa puede imprimir 0, 1 o 2. El párrafo específico en C ++ 11 es 12.8p31 que comienza con:

Cuando se cumplen ciertos criterios, se permite que una implementación omita la construcción de copia/movimiento de un objeto de clase, incluso si el constructor de copias/movimientos y/o destructor para el objeto tiene efectos secundarios.

Tenga en cuenta que ambas elisiones de copia no son una optimización que cae en el como si Regla (que requiere que el comportamiento del programa sea consistente con el comportamiento del mismo programa como si No se había producido optimización). El estándar permite explícitamente la implementación generar diferentes comportamientos observables, y depende del programador que su programa no dependa de eso (o acepte los tres resultados posibles).

Nota 2: 1 no se menciona en ninguna de las respuestas, pero es un posible resultado. Hay dos copias potenciales, desde la variable local en la función hasta el objeto devuelto al objeto en main, el compilador no puede elidir a ninguno, una o las dos copias que generan las tres salidas posibles.

Otros consejos

No se puede garantizar. Si intentaba escribir tal garantía de manera coherente, le resultaría imposible hacerlo.

Por ejemplo, considere este código:

std::string f() {
  std::string first("first");
  std::string second("second");
  return FunctionThatIsAlwaysFalse() ? first : second;
}

La función FunctionThatIsAlwaysFalse siempre regresa false, pero solo puedes decir que si haces optimizaciones entre módulos. ¿Debería el estándar requerir que cada compilador realice la optimización entre módulos para que pueda usar RVO en este caso? ¿Cómo funcionaría eso? ¿O debería prohibir que cualquier compilador use RVO cuando se necesitan optimizaciones entre módulos? ¿Cómo funcionaría eso? ¿Cómo puede detener a los compiladores que son lo suficientemente inteligentes como para ver que RVO es posible hacerlo y aquellos que no lo hacen?

¿Deberían la lista estándar de todos los compiladores de optimización que deben admitir con RVO? ¿Y debería prohibir RVO en otros casos? ¿No sería ese tipo de derrotar el punto de optimizar a los compiladores?

¿Y qué pasa con los casos en que el compilador cree que RVO reducirá el rendimiento? ¿Debería requerir que el compilador haga una optimización que cree que es malo? Por ejemplo:

if(FunctionCompilerKnowsHasNoSideEffectsAndThinksMostlyReturnsFalse())
  return F(3); // Here RVO is a pessimization
else
{
 Foo j=F(3);
 return Foo(j);
}

Aquí, si el compilador no está obligado a hacer RTO, si puede evitar el if y la llamada de función, ya que sin RTO, el código es el mismo en ambas mitades. ¿Deberías obligar al compilador a hacer una optimización que cree que empeora las cosas? ¿Por qué?

Realmente no hay forma de hacer una garantía tan de garantía.

Pedánticamente hablando su implementación definida. Los compiladores modernos son lo suficientemente inteligentes como para hacer ese tipo de optimización.

Pero no hay garantía de que el comportamiento sea exactamente el mismo en todas las implementaciones. Eso es lo que Implementación definida el comportamiento se trata.

"permitido" en este contexto significa que 0 o 1 o 2 son salidas conformes estándar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top