我正在尝试编写一些代码来创建序列的函数式样式。我写了一个函数,range(a, b)
,它返回一个你可以迭代的对象,foreach 风格,遍历数字 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;
}
最佳答案
总结现有评论:
range(-4, 5)
创建一个临时对象,并且(在大多数情况下)临时对象只存在到创建它们的完整表达式的末尾。因此,在您的情况下,返回的 _range
对象在 _map
的构造期间有效,但是一旦 _map
从 返回>map
,完整表达式结束,_range
对象被销毁。
也就是说,因为 _map
保存通过 const ref 而不是通过值传递给其构造函数的参数,这意味着当基于范围的 for
开始执行时, 你的 _map::t
已经是一个悬空引用 – 经典 undefined behavior .
要解决此问题,只需让 _map
按值存储其数据成员即可。
关于c++ - 为什么 gcc 使用我的自定义迭代器优化掉这个 C++11 foreach 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14467324/