full - ¿Puede C++ moderno obtener rendimiento gratis?
dev c++ online gratis (2)
A veces se afirma que C ++ 11/14 puede darle un aumento de rendimiento incluso cuando simplemente compila código C ++ 98. La justificación suele estar en la línea de la semántica de movimiento, ya que en algunos casos los constructores de valores r se generan automáticamente o ahora forman parte del STL. Ahora me pregunto si estos casos ya fueron manejados previamente por RVO u optimizaciones de compiladores similares.
Mi pregunta es si podría darme un ejemplo real de un fragmento de código C ++ 98 que, sin modificaciones, se ejecute más rápido utilizando un compilador que admita las nuevas características del lenguaje. Entiendo que no se requiere un compilador conforme estándar para hacer la elisión de copia y solo por esa razón la semántica de movimiento podría generar velocidad, pero me gustaría ver un caso menos patológico, si lo desea.
EDITAR: Solo para que quede claro, no estoy preguntando si los nuevos compiladores son más rápidos que los antiguos, sino que si hay un código que agregue -std = c ++ 14 a los indicadores de mi compilador, se ejecutará más rápido (evite copias, pero si puede llegar a cualquier otra cosa además de mover la semántica, también me interesaría)
Conozco 5 categorías generales en las que recompilar un compilador de C ++ 03 ya que C ++ 11 puede causar aumentos de rendimiento ilimitados que prácticamente no están relacionados con la calidad de la implementación. Estas son todas las variaciones de la semántica de movimiento.
std::vector
reasignación de
std::vector
struct bar{
std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03
cada vez que el búfer de
foo
se reasigna en C ++ 03, copia todos los
vector
en la
bar
.
En C ++ 11, en cambio, mueve la
bar::data
s, que es básicamente gratuita.
En este caso, esto se basa en optimizaciones dentro del
vector
contenedor
vector
.
En todos los casos a continuación, el uso de contenedores estándar es simplemente porque son objetos C ++ que tienen una semántica de
move
eficiente en C ++ 11 "automáticamente" cuando actualiza su compilador.
Los objetos que no lo bloquean y que contienen un contenedor
std
también heredan los constructores de
move
mejorados automáticos.
Fallo de NRVO
Cuando NRVO (optimización del valor de retorno denominado) falla, en C ++ 03 vuelve a copiarse, en C ++ 11 vuelve a caer en movimiento. Las fallas de NRVO son fáciles:
std::vector<int> foo(int count){
std::vector<int> v; // oops
if (count<=0) return std::vector<int>();
v.reserve(count);
for(int i=0;i<count;++i)
v.push_back(i);
return v;
}
o incluso:
std::vector<int> foo(bool which) {
std::vector<int> a, b;
// do work, filling a and b, using the other for calculations
if (which)
return a;
else
return b;
}
Tenemos tres valores: el valor de retorno y dos valores diferentes dentro de la función. Elision permite que los valores dentro de la función se ''fusionen'' con el valor de retorno, pero no entre sí. Ambos no pueden fusionarse con el valor de retorno sin fusionarse entre sí.
El problema básico es que la elisión NRVO es frágil, y el código con cambios que no están cerca del sitio de
return
puede tener reducciones masivas de rendimiento en ese punto sin emitir diagnósticos.
En la mayoría de los casos de falla NRVO, C ++ 11 termina con un
move
, mientras que C ++ 03 termina con una copia.
Devolver un argumento de función
Elision también es imposible aquí:
std::set<int> func(std::set<int> in){
return in;
}
en C ++ 11 esto es barato: en C ++ 03 no hay forma de evitar la copia. Los argumentos de las funciones no se pueden elidir con el valor de retorno, ya que el código de llamada administra la vida útil y la ubicación del parámetro y el valor de retorno.
Sin embargo, C ++ 11 puede moverse de uno a otro.
(En un ejemplo de menos juguete, se podría hacer algo al
set
).
push_back
o
insert
Finalmente, la elisión en contenedores no ocurre: pero C ++ 11 sobrecarga los operadores de inserción de movimiento de valor, lo que guarda copias.
struct whatever {
std::string data;
int count;
whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );
en C ++ 03 se crea
whatever
temporal,
whatever
que se copia en el vector
v
.
Se asignan 2 buffers
std::string
, cada uno con datos idénticos, y uno se descarta.
En C ++ 11 se crea temporalmente
whatever
sea.
La sobrecarga
whatever&&
push_back
whatever&&
entonces
move
s temporalmente al vector
v
.
Se asigna un búfer
std::string
y se mueve al vector.
Un
std::string
vacío se descarta.
Asignación
Robado de la respuesta de @ Jarod42 a continuación.
Elision no puede ocurrir con la asignación, pero se puede mover desde.
std::set<int> some_function();
std::set<int> some_value;
// code
some_value = some_function();
aquí
some_function
devuelve un candidato para eludir, pero debido a que no se utiliza para construir un objeto directamente, no se puede elidir.
En C ++ 03, lo anterior hace que el contenido de lo temporal se copie en
some_value
.
En C ++ 11, se mueve a
some_value
, que básicamente es gratuito.
Para el efecto completo de lo anterior, necesita un compilador que sintetice los constructores de movimiento y la asignación por usted.
MSVC 2013 implementa constructores de movimiento en contenedores
std
, pero no sintetiza constructores de movimiento en sus tipos.
Por lo tanto, los tipos que contienen
std::vector
sy similares no obtienen tales mejoras en MSVC2013, pero comenzarán a obtenerlas en MSVC2015.
clang y gcc han implementado desde hace mucho tiempo constructores de movimientos implícitos.
El compilador de Intel 2013 admitirá la generación implícita de constructores de movimientos si pasa
-Qoption,cpp,--gen_move_operations
(no lo hacen de forma predeterminada en un esfuerzo por ser compatibles con MSVC2013).
si tienes algo como:
std::vector<int> foo(); // function declaration.
std::vector<int> v;
// some code
v = foo();
Tienes una copia en C ++ 03, mientras que tienes una asignación de movimiento en C ++ 11. entonces tienes optimización gratis en ese caso.