11

関数型のシーケンス作成を行うためのコードを書き込もうとしていました。range(a, b)数値 a、a + 1、...、b - 1 を処理するために、foreach スタイルで反復処理できるオブジェクトを返す1 つの関数 を作成しました。次にmap(f, t)、別の反復可能オブジェクトを返す別の関数 を作成しました。シーケンス内の各要素fは、 iterable object の対応する要素で呼び出した結果ですt

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

1 に答える 1

8

既存のコメントを要約すると:

range(-4, 5)一時的なものを作成し、(ほとんどの場合) 一時的なものは、それらが作成された完全な式の終わりまでしか存続しません。したがって、あなたの場合、返さ_rangeれたオブジェクトは の構築中に有効ですが、から返さ_mapれるとすぐに完全な式が終了し、オブジェクトは破棄されます。_mapmap_range

つまり、_map値ではなく const ref によってコンストラクターに渡された引数を保持するため、これは、範囲ベースのfor実行が開始されるまでに、_map::t既にぶら下がっている参照 (古典的な未定義の動作) であることを意味します。

これを修正するには、単純に_mapそのデータ メンバーを値で保存します。

于 2013-01-22T22:25:34.780 に答える