当前位置: 首页 > 知识库问答 >
问题:

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

萧萧迟
2023-03-14

我试图编写一些代码来执行函数式序列的创建。我写了一个函数range(a,b),它返回一个对象,你可以迭代它,foreach样式,以遍历数字a,a 1,...,b - 1。然后我写了另一个函数map(f,t),它返回另一个可迭代对象,其中序列中的每个元素都是使用可迭代对象t的相应元素调用f的结果。

如果我使用< code>-O1或更低版本进行编译,这将按预期工作;使用< code>-O2或更高版本,我的foreach循环(在底部的< code>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个答案

梁浩涆
2023-03-14

总结现有评论:

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

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

要解决此问题,只需让_map按值存储其数据成员。

 类似资料:
  • 我知道这个问题在这个论坛上已经被问过好几次了。但我仍在发帖,因为没有一个答案看起来是具体的。专家们,你们能帮我理解什么时候使用迭代器吗。当我们有一个非常大的数据集时,我们是理想地使用它,还是当我们有大量数据要返回时,将其用作方法的返回类型?

  • 我想为客户数据结构提供一个视图,它有自己的迭代器。我编写了一个小程序来测试它,如下所示。如果我取消对begin()的注释,它就会工作。但是如果我使用DummyIter,那么我会得到一个编译错误。 在我的完整程序中,我实现了一个完整的迭代器,但为了简单起见,我把它缩小到了必要的函数。 我使用的是GCC 11.1.0。我在迭代器中缺少了什么使其符合范围?

  • 问题内容: var x int done := false go func() { x = f(…); done = true } while done == false { } 这是Go代码。我的恶魔告诉我,这是UB代码。为什么? 问题答案: Go Memory Model不保证该程序将始终遵守在goroutine中写入x的值。go常规销毁 部分中提供了一个类似的错误程序作为示例。 在本节中,G

  • 这是一个使用ValArray的简单c程序: 如果我像这样编译并运行它: 产出如预期: 但是,如果我像这样编译和运行它: 输出为: 如果使用优化参数,也会发生同样的情况。 GCC版本是(Archlinux最新版本): 但是,如果我尝试叮当,两者 和 产生相同的正确结果: clang版本是: 我还尝试了在Debian上使用GCC 4.9.2,其中可执行文件会产生正确的结果。 这是GCC中可能存在的错误

  • 问题内容: 谁能告诉我Java +5中Enhanced for loop和Iterators的优点是什么? 问题答案: Stephen Colebourne(Joda- Time,JSR-310等)对优点和缺点进行了很好的总结,针对每个循环迭代控制建议进行了增强,以在Java 7中进行扩展: 功能概要: 扩展Java 5 for-each循环,以允许访问循环索引(无论是第一次还是最后一次迭代),并

  • 问题内容: 我的代码产生了意外的结果。看来我的for循环跳过了第一次迭代,我不明白为什么。 返回…(假设输入的数字是姓名) 为什么第一个get.nextLine()被跳过? 问题答案: 当前,您对Scanner#nextInt的调用不占用换行符,因此将其传递给您的第一次调用,因此 不会 阻塞。 您将需要添加 通话后,您的第一个通话将阻止。