2013-01-22 8 views
11

私は、機能スタイルのシーケンスの作成を行うためのコードを書くことを試みていました。私は1つの関数range(a, b)を書いています。これはforeachスタイルで反復してa、a + 1、...、b-1の数値を返すオブジェクトを返します。次に別の関数map(f, t)を返します。シーケンス中の各要素は、反復可能オブジェクトtの対応する要素を持つfを呼び出した結果である別の反復可能オブジェクトです。gccは私のカスタムイテレータを使ってこのC++ 11 foreachループを最適化するのはなぜですか?

これは、-O1以下を使用してコンパイルすると正常に動作します。 -O2以上では、私のforeachループ(最下部のmain)が完全に最適化され、何も印刷されません。なぜこれが起こるのですか、私は何が間違っていますか?既存のコメントをまとめる

template<typename T> 
struct _range { 
    T a; 
    T b; 

    _range(T a, T b): 
     a(a), 
     b(b) 
    { 
    } 

    struct iterator { 
     T it; 

     iterator(T it): 
      it(it) 
     { 
     } 

     bool operator!=(const iterator &other) const 
     { 
      return it != other.it; 
     } 

     void operator++() 
     { 
      ++it; 
     } 

     T operator*() const 
     { 
      return it; 
     } 
    }; 

    iterator begin() const 
    { 
     return iterator(a); 
    } 

    iterator end() const 
    { 
     return iterator(b); 
    } 
}; 

template<typename T> 
_range<T> range(const T a, const T b) 
{ 
    return _range<T>(a, b); 
} 

template<typename F, typename T> 
struct _map { 
    const F &f; 
    const T &t; 

    _map(const F &f, const T &t): 
     f(f), 
     t(t) 
    { 
    } 

    struct iterator { 
     const F &f; 
     typename T::iterator it; 

     iterator(const F &f, typename T::iterator it): 
      f(f), 
      it(it) 
     { 
     } 

     bool operator!=(const iterator &other) const 
     { 
      return it != other.it; 
     } 

     void operator++() 
     { 
      ++it; 
     } 

     int operator*() const 
     { 
      return f(*it); 
     } 
    }; 

    iterator begin() const 
    { 
     return iterator(f, t.begin()); 
    } 

    iterator end() const 
    { 
     return iterator(f, t.end()); 
    } 
}; 

template<typename F, typename T> 
_map<F, T> map(const F &f, const T &t) 
{ 
    return _map<F, T>(f, t); 
} 

#include <algorithm> 
#include <cstdio> 

int main(int argc, char *argv[]) 
{ 
    for (int i: map([] (int x) { return 3 * x; }, range(-4, 5))) 
     printf("%d\n", i); 

    return 0; 
} 
+0

バグかもしれませんか? Clang ++では、O1とO2の両方の最適化レベルでうまく動作します。 –

+7

'_map'がconst refを格納するのではなく、値でメンバーを格納するようにしてください。 (あなたの 'range'オブジェクトがあなたが望んでいたよりも早く破壊されていると思われます。) – ildjarn

+3

@ildjarnは正しいと思います:一時的なものは、それがバインドされている定数参照が生きている限り、バインドされている参照は 'map'のコンストラクタの引数です。コンストラクタが返ってくると、参照が範囲外になり、一時的なものが破棄されます。 –

答えて

8

range(-4, 5)は(ほとんどの場合)一時的に作成し、それが作成されたフル式の終わりまで、唯一のライブ一時ここに私のコードです。したがって、返された_rangeオブジェクトは、_mapの構築中に有効ですが、上記の_mapmapから返されると、完全表現が終了し、_rangeオブジェクトが破棄されます。言っ

_mapはconstの参照ではなく値によって、そのコンストラクタに渡された引数を保持しているため、これは範囲ベースforが実行を開始した時点で、あなたの_map::tはすでにダングリング参照であることを意味 - 古典undefined behavior

これを修正するには、_mapに値でデータメンバを格納するだけです。

関連する問題