2016-07-13 17 views
11

Jest to prosty program w C++ z wykorzystaniem valarrays:Dlaczego optymalizacja GCC nie działa z valarrays?

#include <iostream> 
#include <valarray> 

int main() { 
    using ratios_t = std::valarray<float>; 

    ratios_t a{0.5, 1, 2}; 
    const auto& res (ratios_t::value_type(256)/a); 
    for(const auto& r : ratios_t{res}) 
     std::cout << r << " " << std::endl; 
    return 0; 
} 

Jeśli mogę skompilować i uruchomić go tak:

g++ -O0 main.cpp && ./a.out 

Wyjście jest zgodnie z oczekiwaniami:

512 256 128 

Jednakże, jeśli Kompiluję i uruchamiam w następujący sposób:

g++ -O3 main.cpp && ./a.out 

Wyjście jest:

0 0 0 

To samo dzieje się, jeśli mogę użyć -O1 parametr optymalizacji.

wersja GCC jest (ostatnie w ArchLinux):

$ g++ --version 
g++ (GCC) 6.1.1 20160707 

Jednak gdy próbuję z brzękiem, zarówno

clang++ -std=gnu++14 -O0 main.cpp && ./a.out 

i

clang++ -std=gnu++14 -O3 main.cpp && ./a.out 

produkują ten sam wynik poprawny:

512 256 128 

wersja Clang to:

$ clang++ --version 
clang version 3.8.0 (tags/RELEASE_380/final) 

Ja również próbowałem z GCC 4.9.2 na Debianie, gdzie wykonywalny produkuje poprawny wynik.

Czy jest to możliwy błąd w GCC lub czy robię coś nie tak? Czy ktoś może to odtworzyć?

EDYCJA: Udało mi się odtworzyć problem również w wersji Homebrew GCC 6 na Mac OS.

+0

Korzystanie http://melpon.org/wandbox Wydaje się, że zmiany w zachowaniu od 4.9.3 do 5.1. – NathanOliver

+0

Niestety, w moim codebase udało mi się również odtworzyć podobny problem (ale z uint32_t) nawet w GCC 4.9.3, jednak działa on po umieszczeniu w minimalnym przykładzie. Prowadzę dochodzenie ... – DoDo

Odpowiedz

6

valarray i auto nie mieszają się dobrze.

ta tworzy tymczasowy obiekt, a następnie stosuje operator/ do niego:

const auto& res (ratios_t::value_type(256)/a); 

libstdC++ valarray wykorzystuje szablony ekspresji tak, że operator/ zwraca lekki obiekt, który odnosi się do oryginalnych argumentów i ocenia je leniwie. Używa się wartości const auto&, która powoduje, że szablon wyrażeń jest powiązany z odwołaniem, ale nie przedłuża okresu istnienia tymczasowego, do którego odwołuje się szablon wyrażeń, a więc gdy ocena się zakończy, tymczasowy stan wykracza poza zakres, a jego pamięć została ponownie wykorzystane.

To będzie działać dobrze, jeśli nie:

ratios_t res = ratios_t::value_type(256)/a; 
+0

Dziękuję za szczegółową odpowiedź. Przyjmę to. Chciałbym tylko zauważyć, że nawet jeśli piszę 'auto res (ratio = t = value_type (256)/a)', nadal otrzymuję ten sam wynik z włączonymi optymalizacjami. Jednak Twoja sugestia działa (tzn. Nie używa 'auto'). Zarówno oryginalny kod jak i msvc działały poprawnie. – DoDo

+0

Tak, ponieważ 'auto' dedukuje typ szablonu wyrażeń, który zawiera odniesienie do wygasłego tymczasowego. Musisz jawnie utworzyć 'valarray', aby wymusić ewaluację zanim tymczasowy zniknie. Jak już powiedziałem, 'auto' i' valarray' nie mieszają się dobrze. –

+0

https://gccnunu.org/bugzilla/show_bug.cgi?id=57997 to bardzo podobny problem. –

3

Jest to wynikiem niestarannego wykonania operator/ (const T& val, const std::valarray<T>& rhs) (i prawdopodobnie innych operatorów ponad valarrays) za pomocą lazy ocena:

#include <iostream> 
#include <valarray> 

int main() { 
    using ratios_t = std::valarray<float>; 

    ratios_t a{0.5, 1, 2}; 
    float x = 256; 
    const auto& res (x/a); 
    // x = 512; // <-- uncommenting this line affects the output 
    for(const auto& r : ratios_t{res}) 
     std::cout << r << " "; 
    return 0; 
} 

Z linii "x = 512" powiedział out, wyjście jest

512 256 128 

Odkomentuj tę linię, a wynik zmieni się na

1024 512 256 

Ponieważ w twoim przykładzie lewostronny argument operatora podziału jest tymczasowy, wynik jest niezdefiniowany.

UPDATE

Jak Jonathan Wakely prawidłowo pointed out wdrożenie leniwy ocena bazie staje się problemem w tym przypadku ze względu na wykorzystanie auto.

+0

Dziękuję za odpowiedź. Jonathan był pierwszy, więc przyjąłem jego odpowiedź, ale twoja jest również bardzo pouczająca. Szkoda, że ​​SO nie pozwala zaakceptować wielu odpowiedzi :-). – DoDo

Powiązane problemy