为什么gcc使用我的自定义迭代器优化了这个C++ 11 foreach循环?

Veg*_*ard 11 c++ foreach iterator c++11

我试图编写一些代码来进行序列的功能式创建.我编写了一个函数,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;
}
Run Code Online (Sandbox Code Playgroud)

ild*_*arn 8

总结现有意见:

range(-4, 5)创建一个临时的,并且(在大多数情况下)临时表只存活到它们被创建的完整表达式的结尾.因此,在您的情况下,返回的_range对象在构造期间是有效的_map,但是一旦_map从中返回map,则完整表达式结束并且_range对象被销毁.

也就是说,因为_map持有通过const ref而不是值传递给它的构造函数的参数,这意味着在基于范围的for开始执行时,你_map::t已经是一个悬空引用 - 经典的未定义行为.

要解决此问题,只需_map按值存储其数据成员即可.