2016-07-13 16 views
11

これはvalarraysを使用して簡単なC++プログラムです:GCCの最適化がvalarrayで機能しないのはなぜですか?

#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; 
} 

私はコンパイルして、このようにそれを実行した場合:

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

期待通りに出力されている:

512 256 128 

しかし、場合私はこのようにコンパイルして実行します:

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

出力は次のようになります。私は-O1最適化パラメータを使用している場合

0 0 0 

同じことが起こります。

GCCのバージョンは、(最新のArchlinuxに)ある:

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

しかし、私は打ち鳴らすとしようとした場合、両方が

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

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

が同じ正しい結果を生成します。

512 256 128 

クランバージョンです:

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

私はまた、実行可能ファイルは、正しい結果を生成するのDebian、上のGCC 4.9.2で試してみました。

これはGCCのバグでしょうか、何か間違っていますか?誰でもこれを再現できますか?

EDIT:私はMacBookのGCC 6の自作バージョンでもこの問題を再現しました。

+0

をhttp://melpon.org/wandboxそれが4.9.3から5.1への動作の変更を表示されます使用します。 – NathanOliver

+0

残念ながら、私のコードベースでは、GCC 4.9.3でも同様の問題(ただしuint32_t)を再現することができましたが、最小限の例ではうまくいきます。私は調査中です... – DoDo

答えて

6

valarrayおよびautoはよく混合しない。

これは一時的なオブジェクトを作成し、それにoperator/を適用します。

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

operator/を元の引数を参照し、遅延し、それらを評価し、軽量オブジェクトを返すようにlibstdC++ valarrayは、式テンプレートを使用しています。 const auto&を使用すると、エクスプレッションテンプレートが参照にバインドされますが、エクスプレッションテンプレートが参照するテンポラリの存続期間は延長されません。したがって、評価が発生すると一時的なスコープが外れ、そのメモリは再利用される。

それはあなたがしなければ正常に動作します:

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

詳細な回答ありがとうございます。私はそれを受け入れる。私は 'auto res(ratios_t :: value_type(256)/ a)'を書いても、私はまだ最適化を有効にして同じ結果を得ていることに気付きたいと思います。しかし、あなたの提案はうまくいきます(つまり 'auto'を使わない)。 clangとmsvcの両方のオリジナルコードが正しく機能していました。 – DoDo

+0

はい、 'auto'は期限切れの一時的な参照への参照を含む式テンプレートの型を推測するためです。一時的なものがなくなる前に評価を強制するには、 'valarray'を明示的に作成する必要があります。私が言ったように、 'auto'と' valarray'はよく混ざりません。 –

+0

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57997は非常によく似た問題です。 –

3

それは遅延評価を使用してoperator/ (const T& val, const std::valarray<T>& rhs)の不注意な実装(およびvalarraysオーバーおそらく他の事業者)の結果です:コメントアウト「x = 512」行で

#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; 
} 

、出力は

512 256 128 
です

その行のコメントを外して出力を

1024 512 256 
に変更します。

あなたの例では、除算演算子の左辺引数が一時的なので、結果は未定義です。

UPDATE

pointed out正しくJonathan Wakelyとして、遅延評価ベースの実装が原因autoの使用この例では問題となります。

+0

あなたの答えをありがとう。ジョナサンが最初だったので私は彼の答えを受け入れましたが、あなたも非常に有益です。あまりにも悪いので、複数の回答を受け入れることはできません:-)。 – DoDo

関連する問題