O código a seguir funciona bem com cl.exe (produz a saída esperada 2, 9.9).
Com g++ ele não produz nenhuma saída com otimização -O3 e a saída errada (1,10) com otimização -O1 e -O2.
A versão do g++ é 12.2.0, executada na janela de comando do Windows 10.
Tenho expectativas erradas sobre auto e valarray ou estou apenas fazendo algo estúpido?
#include <iostream>
#include <valarray>
int main()
{
double dx = 0.1;
std::valarray<double> Y{ 1.0, 10.0 };
// Works fine with g++, all optimisation levels
// std::valarray<double> dY1 = dx * std::valarray<double>{ Y[1], -Y[0] };
// Y += dY1;
// Fails completely with g++ -O3; gives wrong answer with -O1 and -O2; works fine with cl.exe
auto dY2 = dx * std::valarray<double>{ Y[1], -Y[0] };
Y += dY2;
std::cout << Y[0] << '\t' << Y[1] << '\n';
}
libstdc++ usa modelos de expressão para implementar operações valarray.
Isso ocorre para que coisas como
X = 3 * Y + 2
possam ser implementadas como um único loop, em vez de um loop multiplicar por 3 e outro adicionando 2.Entretanto, esses modelos de expressão armazenam referências aos seus operandos. Você
std::valarray<double>{ Y[1], -Y[0] }
é temporário, então imediatamente se torna uma referência pendente.Copiar para um real
std::valarray<double>
realmente avaliaria o modelo de expressão antes que o temporário morresse. Você também pode ver que isso funciona se você não usar um temporário: