Почему gcc оптимизирует этот цикл С++ 11 foreach с помощью моего пользовательского итератора?

Я пытался написать какой-то код для создания последовательностей в функциональном стиле. Я написал одну функцию range(a, b), которая возвращает объект, который вы можете перебирать, foreach-style, для прохождения чисел a, a + 1,..., b - 1. Затем я написал еще одну функцию, map(f, t), который возвращает другой итерируемый объект, где каждый элемент в последовательности является результатом вызова f с соответствующим элементом итерируемого объекта 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;
}

Ответ 1

Подведение итогов существующих комментариев:

range(-4, 5) создает временный, и (в большинстве случаев) временные ряды живут только до конца полного выражения, в котором они созданы. Поэтому в вашем случае возвращаемый объект _range действителен во время построения _map, но как только указанный _map возвращается из map, полное выражение заканчивается и объект _range уничтожается.

Тем не менее, потому что _map содержит аргументы, переданные его конструктору по const ref, а не по значению, это означает, что к моменту начала работы на основе диапазона for ваш _map::t уже является обвязывающей ссылкой - классическое поведение undefined.

Чтобы исправить это, просто _map сохраните его данные по значению.